Domanda

Di recente ho perso circa mezz'ora per rintracciare questo strano comportamento in NSLog (...):

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

La riga (A) stampa l'atteso "num = 123, testo = abc", ma la riga (B) stampa "num = 123, testo = (null) ".

Ovviamente, stampare un long long con % d è un errore, ma qualcuno può spiegare perché causerebbe la stampa di text come nulla?

È stato utile?

Soluzione

Hai appena incasinato l'allineamento di memoria sul tuo stack. Presumo che tu usi il più recente prodotto Apple con processore x86. Tenendo conto di questi presupposti, il tuo stack appare così in entrambe le situazioni:

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

Nella prima situazione hai messo nello stack 8 byte e poi 4 byte. E poi a NSLog viene richiesto di recuperare dallo stack 12 byte (8 byte per % lld e 4 byte per % @ ).

In una seconda situazione, si ordina a NSLog di prendere prima 4 byte (% d ). Poiché la tua variabile è lunga 8 byte e contiene un numero molto piccolo, i suoi 4 byte superiori saranno 0. Quindi, quando NSLog proverà a stampare il testo, prenderà nil dallo stack.

Dato che l'invio di un messaggio a nil è valido in Obj-C NSLog invierà semplicemente description: a nil probabilmente non riceverà nulla e quindi stampa ( nullo).

Alla fine, poiché Objective-C è solo C con aggiunte, il chiamante ripulisce tutto questo casino.

Altri suggerimenti

La modalità di implementazione dei vararg dipende dal sistema. Ma ciò che sta probabilmente accadendo è che gli argomenti sono memorizzati consecutivamente in un buffer, anche se gli argomenti possono avere dimensioni diverse. Quindi i primi 8 byte (supponendo che sia la dimensione di un long long int ) degli argomenti è il long long int , e i successivi 4 byte (supponendo che sia la dimensione di un puntatore sul sistema) è il puntatore NSString .

Quindi quando dici alla funzione che si aspetta un int e quindi un puntatore, si aspetta che i primi 4 byte siano il int (supponendo che sia la dimensione di un int ) e i successivi 4 byte come puntatore. A causa della particolare endianness e disposizione degli argomenti sul tuo sistema, i primi 4 byte del long long int sembrano essere i byte meno significativi del tuo numero, quindi stampa 123. Quindi per il puntatore all'oggetto , legge i successivi 4 byte, che in questo caso sono i byte più significativi del tuo numero, che è tutto 0, quindi viene interpretato come un puntatore nil . Il puntatore effettivo non viene mai letto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top