Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

c - Why does printf print random value with float and integer format specifier

I wrote a simple code on a 64 bit machine

int main() {
    printf("%d", 2.443);
}

So, this is how the compiler will behave. It will identify the second argument to be a double hence it will push 8 bytes on the stack or possibly just use registers across calls to access the variables. %d expects a 4 byte integer value, hence it prints some garbage value.

What is interesting is that the value printed changes everytime I execute this program. So what is happening? I expected it to print the same garbage value everytime not different ones everytime.

See Question&Answers more detail:os

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

1 Answer

0 votes
by (71.8m points)

It's undefined behaviour, of course, to pass arguments not corresponding to the format, so the language cannot tell us why the output changes. We must look at the implementation, what code it produces, and possibly the operating system too.

My setup is different from yours,

Linux 3.1.10-1.16-desktop x86_64 GNU/Linux (openSuSE 12.1)

with gcc-4.6.2. But it's similar enough that it's reasonable to suspect the same mechanisms.

Looking at the generated assembly (-O3, out of habit), the relevant part (main) is

.cfi_startproc
subq    $8, %rsp             # adjust stack pointer
.cfi_def_cfa_offset 16
movl    $.LC1, %edi          # move format string to edi
movl    $1, %eax             # move 1 to eax, seems to be the number of double arguments
movsd   .LC0(%rip), %xmm0    # move the double to the floating point register
call    printf
xorl    %eax, %eax           # clear eax (return 0)
addq    $8, %rsp             # adjust stack pointer
.cfi_def_cfa_offset 8
ret                          # return

If instead of the double, I pass an int, not much changes, but that significantly

movl    $47, %esi            # move int to esi
movl    $.LC0, %edi          # format string
xorl    %eax, %eax           # clear eax
call    printf

I have looked at the generated code for many variations of types and count of arguments passed to printf, and consistently, the first double (or promoted float) arguments are passed in xmmN, N = 0, 1, 2, and the integer (int, char, long, regardless of signedness) are passed in esi, edx, ecx, r8d, r9d and then the stack.

So I venture the guess that printf looks for the announced int in esi, and prints whatever happens to be there.

Whether the contents of esi are in any way predictable when nothing is moved there in main, and what they might signify, I have no idea.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...