Pergunta

Recentemente desperdiçado cerca de meia hora rastrear esse comportamento estranho em NSLog (...):

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

Line (A) imprime o esperado "num = 123, text = abc", mas a linha (B) imprime "num = 123, text = (null) ".

Obviamente, imprimindo um long long com %d é um erro, mas alguém pode explicar por que isso causaria text a ser impresso como nulo?

Foi útil?

Solução

Você só errei alinhamento de memória em seu stack. Presumo que você usa mais novo produto da Apple com processador x86. Tomando estes pressupostos em conta a sua aparência pilha como que em ambas as situações:

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

Na primeira situação que você colocar na pilha 8 bytes e, em seguida, 4 bytes. E que NSLog é instruído a levar de volta da pilha de 12 bytes (8 bytes para %lld e 4 bytes para %@).

Na segunda situação, você instruir NSLog primeiro tomar 4 bytes (%d). Desde sua variável é de 8 bytes de comprimento e possui número muito pequeno seus superiores 4 bytes será 0. Então, quando NSLog vai tentar imprimir texto vai demorar nil de pilha.

Uma vez que o envio de mensagem para nil é válida em Obj-C NSLog só vai enviar description: para nil obter provavelmente nada e, em seguida, imprimir (null).

No final desde Objective-C é apenas C com adições, chamador limpa toda essa confusão.

Outras dicas

Como varargs são implementadas é dependente do sistema. Mas o que é provável acontecer é que os argumentos são armazenados consecutivelyly em um buffer, mesmo que os argumentos podem ter tamanhos diferentes. Assim, os primeiros 8 bytes (assumindo que é do tamanho de um long long int) dos argumentos é o long long int, e os próximos 4 bytes (assumindo que é do tamanho de um ponteiro em seu sistema) é o ponteiro NSString.

Então, quando você diga a função que espera um int e, em seguida, um ponteiro, ele espera que os primeiros 4 bytes para ser o int (assumindo que é o tamanho de um int) e os próximos 4 bytes para ser o ponteiro. Por causa da ordenação particular e arranjo dos argumentos em seu sistema, os primeiros 4 bytes do long long int passa a ser os bytes menos significativos do seu número, então ele imprime 123. Então, para o ponteiro de objeto, ele lê os próximos 4 bytes, que neste caso é a maioria dos bytes significativas de seu número, que é tudo 0, de modo que é interpretado como um ponteiro nil. O ponteiro real nunca é lido.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top