I recently wasted about half an hour tracking down this odd behavior in NSLog(...):
NSString *text = @"abc";
long long num = 123;
NSLog(@"num=%lld, text=%@",num,text); //(A)
NSLog(@"num=%d, text=%@",num,text); //(B)
Line (A) prints the expected "num=123, text=abc", but line (B) prints "num=123, text=(null)".
Obviously, printing a long long
with %d
is a mistake, but can someone explain why it would cause text
to be printed as null?
How varargs are implemented is system-dependent. But what is likely happening is that the arguments are stored consecutivelyly in a buffer, even though the arguments may be different sizes. So the first 8 bytes (assuming that's the size of a
long long int
) of the arguments is thelong long int
, and the next 4 bytes (assuming that's the size of a pointer on your system) is theNSString
pointer.Then when you tell the function that it expects an
int
and then a pointer, it expect the first 4 bytes to be theint
(assuming that's the size of anint
) and the next 4 bytes to be the pointer. Because of the particular endianness and arrangement of arguments on your system, the first 4 bytes of thelong long int
happens to be the least significant bytes of your number, so it prints 123. Then for the object pointer, it reads the next 4 bytes, which in this case is the most significant bytes of your number, which is all 0, so that gets interpreted as anil
pointer. The actual pointer never gets read.You just messed up memory alignment on your stack. I assume than you use newest Apple product with x86 processor. Taking these assumptions into account your stack looks like that in both situations:
In first situation you put on stack 8 bytes and then 4 bytes. And than NSLog is instructed to take back from stack 12 bytes (8 bytes for
%lld
and 4 bytes for%@
).In second situation you instruct NSLog to first take 4 bytes (
%d
). Since your variable is 8 bytes long and holds really small number its upper 4 bytes will be 0. Then when NSLog will try to print text it will takenil
from stack.Since sending message to
nil
is valid in Obj-C NSLog will just senddescription:
tonil
get probably nothing and then print (null).In the end since Objective-C is just C with additions, caller cleans up whole this mess.