Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
298 views
in Technique[技术] by (71.8m points)

c - What is the behavior of printing NULL with printf's %s specifier?

Came across an interesting interview question:

test 1:
printf("test %s
", NULL);
printf("test %s
", NULL);

prints:
test (null)
test (null)

test 2:
printf("%s
", NULL);
printf("%s
", NULL);
prints
Segmentation fault (core dumped)

Though this might run fine on some systems, atleast mine is throwing a segmentation fault. What would be the best explanation of this behavior? Above code is in C.

Following is my gcc info:

deep@deep:~$ gcc --version
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...