void* , compilation, taille inconnue

void* , compilation, taille inconnue - C++ - Programmation

Marsh Posté le 01-02-2009 à 18:30:58    

Hi,
 

Code :
  1. int main()
  2. {
  3. void * p;
  4. std::string s("tintin" );
  5. p=reinterpret_cast<void*>(&s);
  6. }


 
Que faut-il faire pour pouvoir pointer string avec p, sans que cela fasse une erreur de compilation ?
Merci.


---------------
je connais tout, je ne sais rien, seule certitude, à vouloir trop on finit par tout perdre.
Reply

Marsh Posté le 01-02-2009 à 18:30:58   

Reply

Marsh Posté le 01-02-2009 à 18:35:56    

std::cout << *reinterpret_cast<std::string*>(p) << std::endl;


[:spamafote]

 

Ou alors je n'ai pas compris la question.


Message édité par Elmoricq le 01-02-2009 à 18:38:24
Reply

Marsh Posté le 01-02-2009 à 18:58:27    

mais sous visual 2008 express ça passe pas, le compilo me sort ça :
 
 error C2036: 'void *' : taille inconnue
 
avec ces 3 lignes de code :
 

Code :
  1. void * p;
  2. std::string s("tintin" );
  3. p=reinterpret_cast<string*>(&s);


Message édité par frenchtoucco le 01-02-2009 à 18:59:06

---------------
je connais tout, je ne sais rien, seule certitude, à vouloir trop on finit par tout perdre.
Reply

Marsh Posté le 01-02-2009 à 19:00:20    

(Edité suite au croisement des messages)
 
Ton premier code compile si on ajoute un

Code :
  1. #include <string>


 
Ton second code compile même sans reinterpret_cast<>
 
Est-ce que tu peux préciser ta question?
 
(J'ai pas VC++, mais donne quand même un code complet qui reproduit ton problème)


Message édité par Un Programmeur le 01-02-2009 à 19:03:22
Reply

Marsh Posté le 01-02-2009 à 19:09:28    

mais aprés quand on essaye de déréférencé p , (*p), le compilo sors:
 
error C2100: indirection non conforme


---------------
je connais tout, je ne sais rien, seule certitude, à vouloir trop on finit par tout perdre.
Reply

Marsh Posté le 01-02-2009 à 19:09:54    

en faite c'est préciement ça qui me pose problème le déréfencement d'un void*


---------------
je connais tout, je ne sais rien, seule certitude, à vouloir trop on finit par tout perdre.
Reply

Marsh Posté le 01-02-2009 à 19:15:34    

frenchtoucco a écrit :

en faite c'est préciement ça qui me pose problème le déréfencement d'un void*


 
J'ai du mal à imaginer un contexte où déréférencer un void* a du sens.  Quel problème cherches-tu à résoudre qui t'incite à dérérérencer un void*?

Reply

Marsh Posté le 01-02-2009 à 19:17:51    

c'est plus un code qui sert d'exemple pour afficher la vtable d'une classe, et pour cela j'ai besoin de déférencé un void*:
 

Code :
  1. void print_vtable ( A *  pa )
  2. {
  3.  unsigned  * p = reinterpret_cast<unsigned*>(pa);
  4.  void   * vt = reinterpret_cast<void  * >(p[0]);
  5. ....
  6. vt[0]


---------------
je connais tout, je ne sais rien, seule certitude, à vouloir trop on finit par tout perdre.
Reply

Marsh Posté le 01-02-2009 à 19:35:47    

frenchtoucco a écrit :

c'est plus un code qui sert d'exemple pour afficher la vtable d'une classe, et pour cela j'ai besoin de déférencé un void*:
 

Code :
  1. void print_vtable ( A *  pa )
  2. {
  3.  unsigned  * p = reinterpret_cast<unsigned*>(pa);
  4.  void   * vt = reinterpret_cast<void  * >(p[0]);
  5. ....
  6. vt[0]



 
Si tu veux afficher de la mémoire brute, il faut utiliser des unsigned char* plutôt que des void*.
 
En passant, il y a de bonnes chances pour que ce code ne marche pas (autrement dit que même dans les implémentations utilisant une vtable*, ça ne t'en donne pas toujours le contenu).
 
* Je n'en connais pas d'autres mais ce n'est pas obligatoire.

Reply

Marsh Posté le 01-02-2009 à 20:20:14    

ok


---------------
je connais tout, je ne sais rien, seule certitude, à vouloir trop on finit par tout perdre.
Reply

Marsh Posté le 01-02-2009 à 20:20:14   

Reply

Marsh Posté le 07-02-2009 à 21:54:42    

std::string n'a pas de v-table il me semble. Peu de classe standards ont une v-table. std::exception, si, par exemple.

Reply

Marsh Posté le 07-02-2009 à 22:03:15    

surtout que rien n'impose à un compilo d'ilplanter le polymorphisme avec unt ableau physique pour la vtable.

Reply

Marsh Posté le 07-02-2009 à 22:03:52    

t'en connais qui ne font pas comme ça, par curiosité ?

Reply

Marsh Posté le 07-02-2009 à 22:05:12    

De tête non. Mais je suppose que certaines vielleries ne le font pas genr eborland ou turbo C++ :o
 
Plus serieusement, je ne sais vraiment pas masi j'aime pas trop beaucoup les hack de ce genre qui dependent d'un a priori sur le compilateur.

Reply

Marsh Posté le 07-02-2009 à 22:08:02    

Stroustrup documente les v-table dans son livre, et il parle si peu souvent implémentation, que quand il le fait ça a tendance à être un truc inévitable.
 
Lire les v-table est un bon moyen de savoir si on pointe vers un objet correctement construit. Accessoirement ça donne le type réel d'un objet, car les v-table servent d'apui à typeid. Mais je suis d'accord avec toi sur le fait que c'est pas portable du tout, c'est à reserver au debug sur un compilo spécifique.

Reply

Marsh Posté le 07-02-2009 à 22:13:00    

ouaip.
 
Apres bon, un objet correctement construit, si t'as fait de belle classe avec une strong exception safety, c'est evident. Mais bon.
 
Quant à typeid [:vomi]

Reply

Marsh Posté le 08-02-2009 à 09:58:29    

jesus_christ a écrit :

t'en connais qui ne font pas comme ça, par curiosité ?


 
Pour d'autres langages que le C++, oui.
 
Dans un contexte de C++ traditionnel -- avec un éditeur de liens qui ne fait presque rien -- c'est difficile de faire foncièrement différemment.  Mais avec la montée des optimisations à l'édition de liens, il me semble probable que certains poussent plus loin la seule optimisation qui est parfois faite -- bypasser la vtable quand on connait le type statique.

Reply

Marsh Posté le 08-02-2009 à 11:25:41    

oui, mais l'optimization à la liaison, ou même simplement à la compile, permet de transformer un appel virtuel en appel static quand le type est connu (ce qui est rarement le cas quand on utilise le polymorphisme, justement) mais ça ne permet pas au compilo de jetter la v--table, qui est de toute façon incluse parmis les membre de la classe, en en modifiant la taille, et l'optimisation n'a pas le droit de changer la taille des types.
 

Code :
  1. struct A
  2. {
  3.     int n;
  4. };
  5. struct B
  6. {
  7.     virtual ~B() {} // pour avoir une vtable
  8.     int n;
  9. };
  10. int main()
  11. {
  12.     A a;
  13.     B b; // vtable inutile
  14.     std::cout << sizeof a << ' ' << sizeof b << '\n';
  15. }


 
Ca devrait afficher, sur une machine 32-bits
4 8
Quelque soit le niveau d'optimisation.

Reply

Marsh Posté le 08-02-2009 à 12:13:23    

jesus_christ a écrit :

oui, mais l'optimization à la liaison, ou même simplement à la compile, permet de transformer un appel virtuel en appel static quand le type est connu (ce qui est rarement le cas quand on utilise le polymorphisme, justement)

 

Je n'ai jamais dit le contraire.  Mais si par hasard entre dans spec un programme qui va en profiter, je te garanti que dans les deux ans qui suivent il y aura des compilateurs pour faire cette optimisation.  Voir celui de Sun qui s'est mis à transformer

 
Code :
  1. struct s {
  2.    int x;
  3.    int y;
  4. } table[UN_GRAND_NOMBRE];
 

en

 
Code :
  1. int x[UN_GRAND_NOMBRE];
  2. int y[UN_GRAND_NOMBRE];
 
Citation :

mais ça ne permet pas au compilo de jetter la v--table, qui est de toute façon incluse parmis les membre de la classe, en en modifiant la taille, et l'optimisation n'a pas le droit de changer la taille des types.

 

D'après moi, un programme conforme ne peut pas dépendre de la différence.

 
Citation :

Ca devrait afficher, sur une machine 32-bits
4 8
Quelque soit le niveau d'optimisation.

 

Ca va vraisemblablement le faire.  Mais j'ai pas confiance en l'avenir pour ça.


Message édité par Un Programmeur le 08-02-2009 à 12:13:43
Reply

Marsh Posté le 08-02-2009 à 12:19:14    

Sun transforme les array-of-structure en structure-of-array ?
Ok c'est un peut mieux pour les perfs, mais j'ai un doute sur la validité du code derrière.
 
Si on fait
s* p = &table[42];
il fait comment le compilo ? p ne pointe plus vers un struct s ?

Reply

Marsh Posté le 08-02-2009 à 12:35:36    

je suppose qu'il doit inferer les types afin de pas SoAifier n'importe comment. De la meme manière que les vectorisateurs automatiques s'arretent vite des que tu fais des trucs chelou sur tes valeurs.

Reply

Marsh Posté le 08-02-2009 à 12:39:14    

oui ça doit être ça, mais dès que le type est exposé à l'extérieur, genre vers un DLL/.so dont il ne connait pas le code, il doit s'arréter aussi. En gros ça marche pour une utilisation restreinte et dans des unités de compilation bien isolées. Pourquoi pas...

Reply

Marsh Posté le 08-02-2009 à 12:43:57    

bah ca sert parait il. Je trouve ca limité et nevalant pas le label "vectorisateur automatique" amis tout le monde de la compil se paluche la dessus alors qu'arreter de faire de l'optimsiation aprés la RI au lieu de avant me parait mieux ...

Reply

Marsh Posté le 08-02-2009 à 12:56:17    

jesus_christ a écrit :

oui ça doit être ça, mais dès que le type est exposé à l'extérieur, genre vers un DLL/.so dont il ne connait pas le code, il doit s'arréter aussi. En gros ça marche pour une utilisation restreinte et dans des unités de compilation bien isolées. Pourquoi pas...


 
Je l'ai dit, c'est le genre de choses qui sont faites pour gagner quelques points sur SPEC... (j'ai déjà entendu des rumeurs comme quoi certains compilateurs étaient tellement bien ajustés à SPEC que changer le nom de variable désactivait des optimisations)  Les conditions de validité sont tellement restreintes que ça me semble aussi du temps perdu que d'implémenter cela.  Mais je ne suis pas un grand utilisateur de calcul numérique, si ça tombe ma vision des choses est biaisée.

Reply

Marsh Posté le 09-02-2009 à 22:02:36    

frenchtoucco a écrit :

c'est plus un code qui sert d'exemple pour afficher la vtable d'une classe, et pour cela j'ai besoin de déférencé un void*:
 

Code :
  1. void print_vtable ( A *  pa )
  2. {
  3.  unsigned  * p = reinterpret_cast<unsigned*>(pa);
  4.  void   * vt = reinterpret_cast<void  * >(p[0]);
  5. ....
  6. vt[0]



 
Pour préciser un peu le problème, tu ne peux pas écrire vt[0], parce que le résultat aurait le type "void", ce qui n'a aucun sens. Par exemple si tu écrivais vt[1], il devrait aller chercher où ? à l'adresse de vt + 1 ? ou vt + 4 ? il ne connait pas la taille de chaque élément du tableau que tu veux lire, donc il ne peut rien faire.
 
Et d'ailleurs en écrivant vt[0], tu veux en faire quoi ? l'affecter à une variable ?
 
tu pourrais par exemple écrire int a = ((int*)vt)[0] mais comme d'autres l'ont dit, tu peux tomber sur un peu n'importe quoi avec ton code, selon le compilateur etc.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed