Question

J'ai récemment perdu environ une demi-heure à rechercher ce comportement étrange dans NSLog (...):

NSString *text = @"abc";
long long num = 123;
NSLog(@"num=%lld, text=%@",num,text); //(A)
NSLog(@"num=%d, text=%@",num,text); //(B)

La ligne (A) imprime l'attendu "num = 123, text = abc", mais la ligne (B) imprime "num = 123, text = (null) ".

Évidemment, imprimer un long long avec % d est une erreur, mais quelqu'un peut-il expliquer pourquoi cela provoquerait l'impression du texte comme suit: null?

Était-ce utile?

La solution

Vous venez de gâcher l'alignement de la mémoire sur votre pile. Je suppose que vous utilisez le dernier produit Apple avec un processeur x86. En tenant compte de ces hypothèses, votre pile ressemble à celle-ci dans les deux situations:

   |      stack          | first | second |
   +---------------------+-------+--------+
   |        123          |       |  %d    |
   +---------------------+ %lld  +--------+
   |         0           |       |  %@    |
   +---------------------+-------+--------+
   |   pointer to text   | %@    |ignored |
   +---------------------+-------+--------+  

Dans un premier temps, vous mettez en pile 8 octets, puis 4 octets. Et puis, il est demandé à NSLog de reprendre 12 octets (8 octets pour % lld et 4 octets pour % @ ).

Dans le second cas, vous indiquez à NSLog de commencer par prendre 4 octets (% d ). Étant donné que votre variable a une longueur de 8 octets et qu'elle contient un nombre très petit, ses 4 octets supérieurs sont 0. Lorsque NSLog essaiera d'imprimer du texte, il prendra nil dans la pile.

Etant donné que l'envoi du message à nil est valide dans Obj-C, NSLog envoie simplement description: à nil n'obtient probablement rien et puis imprime ( null).

En fin de compte, puisque Objective-C n’est que C avec des ajouts, l’appelant nettoie tout ce bazar.

Autres conseils

La manière dont varargs sont mis en oeuvre dépend du système. Mais ce qui se passe probablement, c’est que les arguments sont stockés de manière consécutive dans une mémoire tampon, même si les arguments peuvent avoir des tailles différentes. Ainsi, les 8 premiers octets (en supposant que ce soit la taille d’un long long int ) des arguments sont le long long int , et les 4 prochains octets (en supposant que ce soit la taille de un pointeur sur votre système) correspond au pointeur NSString .

Ensuite, lorsque vous indiquez à la fonction qu'elle attend un int , puis un pointeur, elle s'attend à ce que les 4 premiers octets soient le int (en supposant que ce soit la taille d'un int ) et les 4 octets suivants comme pointeur. En raison de l’endianisme et de la disposition des arguments de votre système, les 4 premiers octets du long long int se trouvent être les octets les moins significatifs de votre nombre. Il est donc imprimé 123. Ensuite, pour le pointeur de l’objet , il lit les 4 octets suivants, qui dans ce cas sont les octets les plus significatifs de votre nombre, qui sont tous égaux à 0, ce qui est interprété comme un pointeur nil . Le pointeur réel n'est jamais lu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top