First things first: printf
is expecting a valid (i.e. non-NULL)
pointer for its %s argument so passing it a NULL is officially
undefined. It may print "(null)" or it may delete all files on your
hard drive--either is correct behavior as far as ANSI is concerned
(at least, that's what Harbison and Steele tells me.)
That being said, yeah, this is really wierd behavior. It turns out
that what's happening is that when you do a simple printf
like this:
printf("%s
", NULL);
gcc is (ahem) smart enough to deconstruct this into a call to
puts
. The first printf
, this:
printf("test %s
", NULL);
is complicated enough that gcc will instead emit a call to real
printf
.
(Notice that gcc emits warnings about your invalid printf
argument
when you compile. That's because it long ago developed the ability to
parse *printf
format strings.)
You can see this yourself by compiling with the -save-temps
option
and then looking through the resulting .s
file.
When I compiled the first example, I got:
movl $.LC0, %eax
movl $0, %esi
movq %rax, %rdi
movl $0, %eax
call printf ; <-- Actually calls printf!
(Comments were added by me.)
But the second one produced this code:
movl $0, %edi ; Stores NULL in the puts argument list
call puts ; Calls puts
The wierd thing is that it doesn't print the following newline.
It's as though it's figured out that this is going to cause a segfault
so it doesn't bother. (Which it has--it warned me when I compiled
it.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…