Pregunta

Recientemente perdí aproximadamente media hora rastreando este extraño comportamiento en NSLog (...):

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

La línea (A) imprime el esperado " num = 123, text = abc " ;, pero la línea (B) imprime " num = 123, text = (nulo) ".

Obviamente, imprimir un largo largo con % d es un error, pero ¿alguien puede explicar por qué causaría que se imprima text como nulo?

¿Fue útil?

Solución

Acabas de estropear la alineación de la memoria en tu pila. Supongo que usa el producto más nuevo de Apple con procesador x86. Teniendo en cuenta estos supuestos, su pila se ve así en ambas situaciones:

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

En la primera situación, coloca en la pila 8 bytes y luego 4 bytes. Y luego NSLog tiene instrucciones de recuperar de la pila 12 bytes (8 bytes para % lld y 4 bytes para % @ ).

En la segunda situación, le indica a NSLog que primero tome 4 bytes (% d ). Como su variable tiene 8 bytes de longitud y tiene un número realmente pequeño, sus 4 bytes superiores serán 0. Luego, cuando NSLog intente imprimir texto, tomará nil de la pila.

Dado que enviar un mensaje a nil es válido en Obj-C, NSLog enviará descripción: a nil probablemente no reciba nada y luego imprima ( nulo).

Al final, dado que Objective-C es solo C con adiciones, la persona que llama limpia todo este desastre.

Otros consejos

La forma en que se implementan los varargs depende del sistema. Pero lo que probablemente está sucediendo es que los argumentos se almacenan consecutivamente en un búfer, a pesar de que los argumentos pueden ser de diferentes tamaños. Entonces, los primeros 8 bytes (suponiendo que ese sea el tamaño de un long long int ) de los argumentos es el long long int , y los siguientes 4 bytes (suponiendo que ese sea el tamaño de un puntero en su sistema) es el puntero NSString .

Luego, cuando le dice a la función que espera un int y luego un puntero, espera que los primeros 4 bytes sean el int (suponiendo que ese sea el tamaño de un int ) y los siguientes 4 bytes para ser el puntero. Debido a la especificidad y disposición particular de los argumentos en su sistema, los primeros 4 bytes del long long int resultan ser los bytes menos significativos de su número, por lo que imprime 123. Luego, para el puntero del objeto , lee los siguientes 4 bytes, que en este caso son los bytes más significativos de su número, que es todo 0, por lo que se interpreta como un puntero nil . El puntero real nunca se lee.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top