c programming printf format searches expressions

十年热恋 提交于 2019-12-20 05:35:07

问题


I have a small question. I have this piece of code:

#include <stdio.h>

int main(){
    printf("%d, %f, %d\n", 0.9, 10, 'C');
}

And the output is this:

10, 0.900000, 67

But I would have expected:

0, 10.0, 67

But it looks like the printf searches for the corresponding type in the expressions (int and float are turned) Could anyone help me with this problem? Thank you very much!


回答1:


But I would have expected: …

When the format string does not match the types of the arguments in order, the behavior is undefined. Anything can happen. You cannot expect anything (and I do not see why you would expect 0. Maybe you expect printf to use the format string to convert the arguments between floating-point and integer. It just doesn't. It's a variadic function like you could write your own, and the fact that the format string encodes the types of the trailing arguments is not used to convert them).

Modern calling conventions use registers for the first few arguments, and can use registers even for variadic functions. On x86-64, the convention can be for instance that the first floating-point argument to a variadic function can always be expected in the floating-point register xmm0, whereas integer arguments are passed in general-purpose registers %rdi, %rsi, %rdx, … This has the effect that printf("%f %d", 1, 1.0) prints the floating-point argument followed by the integer argument.

As an illustration, here is a short program:

#include <stdio.h>

int main(){
  printf("%d, %f, %d\n", 0.9, 10, 'C');

  printf("%d, %f, %d\n", 10, 0.9, 'C');
}

This is how my compiler (Clang on Mac OS X 10.6) compiles the program:

leaq <memory location of format string>, %rbx

movq    %rbx, %rdi
movsd   <memory location of 0.9 constant>, %xmm0
movl    $10, %esi
movl    $67, %edx
movb    $1, %al
callq   _printf

movq    %rbx, %rdi
movl    $10, %esi
movsd   <memory location of 0.9 constant>, %xmm0
movl    $67, %edx
movb    $1, %al
callq   _printf

…

It is clear that the two calls produce the same result. But in the case of one, it is accidental and only “works” for this particular compiler version and ABI, whereas the other one respects the standard and has to work anywhere.

Again, printf("%d %f", 0.9, 10) is undefined behavior and you should not use it in any circumstances.




回答2:


It is undefined behaviour, so anything can happen.

%d requires an int, but you are passing a double (not a float), so printf takes 4 bytes of the double value and interprets it as an int.

%f requires a double, but you are passing an int. So it takes the 4 byte of the int and 4 bytes from the next memory and interprets it as a double.

You are lucky to pass 16 bytes while printf expects 16 bytes, so the last value is the correct one.




回答3:


The only correct expectation is getting 67 for printing a character using %d format specifier*. The other two printouts are undefined behavior.

it looks like the printf searches for the corresponding type in the expressions

This is only a coincidence. printf has no idea of the types of the actual parameters that you pass. It trusts the format string, and interprets the data sequentially. You can tell what's going on by supplying different numbers, and observing how the output changes.

The numbers that you see is garbage - a double re-interpreted as an int, and an int re-interpreted as a double. Moreover, if the sizes of double and int are different, the first two parameters cross each others' boundaries.

To produce the output that you want add a cast to the first two parameter expressions:

printf("%d, %f, %d\n", (int)0.9, (double)10, 'C');

Note that you do not need to cast the last parameter, because char is promoted to an int as part of processing variable length argument list of printf.

* This produces correct behavior only when there are no mismatches between other parameters and format specifiers; your program has UB even for the last parameter which would be correct if used by itself.



来源:https://stackoverflow.com/questions/31760369/c-programming-printf-format-searches-expressions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!