11
votes

Tout exemple réel de réinterpret_cast modifiant une valeur de pointeur?

Selon la norme C ++, un REINIERPRET_CAST d'un pointeur T * à un autre pointeur de type q * Can Modifier ou ne pas modifier la valeur du pointeur en fonction de la mise en œuvre.

Je suis très intéressé - il existe un exemple réel d'une implémentation C ++ lors de la diffusion d'un pointeur à un autre type de pointeur avec REINERPRET_CAST modifie le pointeur? Quoi et pourquoi est changé là-bas?


5 commentaires

Vous voulez dire, "change la valeur" le pointeur pointe?


@akira: Non, modifie la valeur du pointeur lui-même


Vous voulez dire comme: t * t = 0x13; Q * q = 0x42; t = reintrepret_cast (q); rendements t! = 0x42 ?


@akire: Je suppose, oui. Je ne suis pas sûr de moi, c'est pourquoi je demande. Vous pourriez être intéressé à lire les réponses à la question liée - ils m'ont inspiré à poser cette question.


Donc, vous n'êtes pas sûr de ce que vous demandez? :) Je pense que les réponses supprimées résultaient de la question légèrement incertaine. Oui, la question liée est intéressante.


5 Réponses :


7
votes

Notez que lorsque la norme stipule qu'il peut ou ne peut pas faire quelque chose, cela ne signifie pas qu'il y a une implémentation actuelle qui a ce comportement, seulement qu'ils pourraient.

Le plus proche que je puisse penser est un L'architecture où l'alignement de type était requis par le matériel et une implémentation qui a décidé de corriger l'alignement si nécessaire. Quelque chose comme: xxx

Il pourrait y avoir une exigence que pour A soit un pointeur valide, il doit adresser une position de mémoire de 8, tandis que L'argument q avec des exigences d'alignement moindre pourrait indiquer n'importe quelle adresse mémoire.


0 commentaires

1
votes
class A1 { int a1; };
class A2 { int a2; };

class B: public A1, public A2 { };

#define DBG(val)  cout << #val << ": " << val << endl

// test code
B b;
DBG(&b);                                           // prints 0x42

void *p_blank = &b;
DBG(p_blank);                                      // prints 0x42
A2 *p_a2 = &b; 
DBG(p_a2);                                         // prints 0x46
void *p_reinterpreted = reinterpret_cast<A2*>(&b);
DBG(p_reinterpreted);                              // prints 0x42
A2 *p_reinterpreted2 = reinterpret_cast<A2*>(&b);
DBG(p_reinterpreted2);                             // prints 0x42
A2 *p_a2 = &b means give me the pointer to an A2 object within the B object.
reinterpret_cast<A2*>(&b) means give me the pointer to b and treat it as an A2 pointer.
The result of this reinterpret_cast has the type 'pointer to A2', therefore it produces no warning when assigned to a void* variable (or to a A2* variable).

4 commentaires

Dans votre exemple, le REINERPRET_CAST ne change pas le tout de la valeur ... Vous êtes d'accord, j'ai peur.


Dans A2 * p_a2 = & B; Vous utilisez une conversion implicite équivalente à static_cast , pas REINIERPRET_CAST .


Il semble que je n'ai pas compris la question correctement. J'ai compris que vous recherchez un cas où réinterpret_cast <> renvoie une valeur différente de celle d'une "adresse" vide ". Je n'ai pas trouvé de clause dans la norme C ++ qui permet à ce que REINERPRET_CAST diffère de Reterpret_cast .


@akira: Lorsque vous effectuez une option implicite (ou static_cast ) à un pointeur de base, le pointeur renvoyé est l'adresse de la sous-classe de cette base dans l'objet. Lorsque vous faites cela avec la première base, les adresses coïncident. S'il y a de multiples héritage, de l'injection à tout sauf la première base (en supposant que la première classe de base n'est pas vide) produira des pointeurs décalés. Dans cet exemple particulier, la classe A1 prend exactement 4 octets.



0
votes

Reterpret_cast ne retournera jamais une adresse différente - il est nécessaire de copier l'adresse exacte.

Dans les cas de héritage multiple, comme David Rodriguez dit, la prise de l'adresse de l'une des bases peut renvoyer une adresse compensée à l'adresse de la première base. Reterpret_cast retournera cette adresse de compensation, mais si vous le traitez comme l'adresse de l'obstruction, l'enfer s'ensuivra.

Pour la refoulement, Static_cast peut renvoyer une adresse différente de celle donnée. Si l'adresse que vous avez est l'une des bases et que cette adresse est en cours d'offset à la première adresse de base, Static_cast retournera une adresse valide pour l'objet prémjectif, ce qui est égal à l'adresse de la première base et donc pas égale à égale. au pointeur passé.

Pour ce faire court: Reterpret_cast vous donne la même adresse, toujours. Static_cast et dynamic_cast peuvent renvoyer une adresse différente, par ex. Dans certains cas impliquant plusieurs héritages.

La différence entre static_cast et dynamic_cast est que static_cast ne vérifie pas si le pointeur que vous donnez est le bon objet pour la distribution, alors assurez-vous de cela avant de l'appeler.


2 commentaires

Une déclaration impliquant des "obligatoires" doit être sauvegardée avec une source. Tout ce que je vois, c'est que vous êtes autorisé à convertir en un pointeur de type moins aligné puis de retour , et "le résultat de toute autre conversion de ce pointeur n'est pas spécifiée". (5.2.10 / 7)


Euh, j'ai complètement manqué les problèmes d'alignement, je peux voir comment cela changerait l'adresse. Merci pour la correction.



1
votes

La source de problèmes la plus probable est sur une machine de vecteur où les opérations scalaires sont définies en termes de vecteurs et qu'un pointeur scalaire consiste en un pointeur pour vecteur avec un index dans le vecteur. Historiquement, l'architecture de crayon originale était comme celle-ci et cela a causé des maux de tête. De nos jours, vous pourriez voir quelque chose comme ça sur un GPU, mais je ne peux pas signaler quelque chose de spécifique au sommet de ma tête.

L'effet le plus probable est la troncature car le type de pointeur de destination manque de bits pour spécifier la partie index. C ++ 11 donne un signe de tête dans cette direction en permettant à tous les types de pointeur d'être REINIERPRET_CAST ED Tant qu'ils ont les mêmes besoins d'alignement. Les bits "zerés" par alignement rigoureux sont autorisés à ne pas exister.

Un pointeur d'objet peut être explicitement converti en un pointeur d'objet de un type différent. Quand une prvalue V de type "pointeur à t1" est converti en type "pointeur à cv t2", le résultat est static_cast (static_cast (v)) si T1 et T2 sont la disposition standard types (3.9) et les exigences d'alignement de T2 ne sont pas plus strictes que ceux de T1, ou si le type est nul. Convertir une prvalue de type "Pointeur sur T1" au type "Pointeur à T2" (où T1 et T2 sont Types d'objet et où les exigences d'alignement de T2 ne sont pas plus strict que ceux de T1) et de retour à son type d'origine génère le Valeur du pointeur d'origine. Le résultat de tout autre pointeur de ce type La conversion n'est pas spécifiée.


0 commentaires