9
votes

& ((nom de structure *) null -> b) dans la déclaration Printf

J'ai trouvé cet échantillon de code dans un livre, mais je ne parviens pas à comprendre l'expression dans la déclaration Printf. et ce programme compile avec succès donner une sortie à 4. Veuillez conseiller ...

void main(){
    unsigned char c;

    typedef struct name {
      long a;
      int b;
      long c;
    }r;

    r re = {3,4,5};
    r *na=&re;

    printf("%d",*(int*)((char*)na + (unsigned int ) & (((struct name  *)NULL)->b)));
}


2 commentaires

Vous savez principal a un type de retour de int in c (et c ++)?


Ce programme exact a été posté il y a 3 ans, je suppose que c'est un livre commun!


3 Réponses :


4
votes

re est une variable locale de type R , c'est-à-dire un nom struct ; Il est généralement alloué sur le pile d'appels .

na est un pointeur sur re .

(non signé INT) & (((((((nom de structure *) null) -> b) pourrait être Comportement non défini (mais je ne suis pas sûr), mais la plupart des compilateurs compileraient que les octets de décalage - de champ B (comme offsetof < / Code> fait, voir offsetof (3) ). Sur ma machine qui pourrait être 8.

(char *) na + Le décalage ci-dessus est souvent la même adresse que & re.b

vous DÉRÉFERENGE que le pointeur, qui est pratiquement & re.b

Je pense que votre code pourrait ne pas être conforme standard (voir Cette réponse pour une certaine argumentation; il pourrait y avoir des machines hypothétiques et des implémentations C où null n'est pas un mot tout zéro-bits, je ne sais pas de telles implémentations), mais Sur toutes les machines que je connais, il devrait imprimer la valeur du champ re.b


4 commentaires

merci@basile .... Permet de rester aux machines que nous savons à propos de ... :)


@HIMANSHUSOURAV: C-FAQ.com/Null/MachExamp.html Just pour que vous sachiez Quelques machines supplémentaires ;-)


@DEduplicator: Mais ces anciennes machines XXème siècle n'existent que dans les musées!


Juste à propos de. C'est pourquoi on peut ignorer un pointeur nul-zéro-zéro-nul-pointeur dans la pratique, principalement. L'UB dans le pointeur-arithmétique cependant, qui peut toujours vous mordre sur des machines modernes, selon (principalement) sur votre implémentation.



9
votes

permet de commencer à partir de la dernière ligne: xxx pré>

permet d'interpréter: p> xxx pré>

est en réalité casting & (((( nom *) NULL) -.> b) code> dans un unsigned int code> p>

& (((nom struct *) NULL) -> b) est l'adresse (il donne un pointeur vers): p>

((  (struct name  *)NULL)->b )


6 commentaires

Sachez que cette construction invoque l'UB cependant.


@Deduplicator est (((nom de structure *) null) -> B) comportement non défini? Cela semble vraiment bien défini pour moi. Pouvez-vous me signaler à un lien qui le spécifie?


@Mmarksegal Great Explication ... merci beaucoup ...


@Mmarksegal: Cela fait du pointeur-arithmétique sur un pointeur NULL, qui est simplement illégal. L'arithmétique du pointeur n'est défini que pour les pointeurs à un objet valide, et uniquement s'il ne s'échappe pas au-delà des limites de l'objet sous-jacent (le pointeur passé d'un objet est explicitement autorisé à).


@Mmarksegal: Ce peut être un comportement non défini non spécifié, même s'il travaille pratiquement partout.


@BasileSarTaryNketch Oui, vous êtes correct. Merci d'avoir fait remarquer cela.



4
votes

Le code:

(unsigned int ) & (((struct name  *)NULL)->b))


2 commentaires

Techniquement, le code est pas Derefenrencing the null pointeur. Mais je pense toujours que c'est un comportement indéfini.


@BasileSelaTaryNkevitch j'ai commencé une nouvelle question pour savoir si cela est réellement ub bien que lors de la première lecture de C11, il ne semble pas beau