在C中两个连续的printf()调用的奇怪行为

时间:2017-07-02 14:42:40

标签: c printf

我在玩C;看看这个:

#include <stdio.h>
#include <stdlib.h>

void main() {
    printf("%d\n", 1.5);
    printf("%f", 0);
}

我期待输出:

0
0.000000

但它会打印:

0
1.500000

第一个printf()是否已将1.5传递给第二个printf()

PS:我知道(%d代表,%f代表浮点数。正如我所提到的,我只是在搞乱代码。

PS2:我使用的是DevC ++&amp;代码::块。

2 个答案:

答案 0 :(得分:13)

根据C标准,行为未定义,以下是您系统上可能发生的情况:

  • 第一次调用printf("%d\n", 1.5); main将浮点值1.5作为第一个XMM注册表中的double传递并调用printf()
  • printf()不修改XMM寄存器,因为如果不执行任何浮点操作来处理格式"%d"。它从不同的位置检索要打印的值:寄存器或堆栈,该值恰好是0
  • 对于第二次调用printf("%f", 0);main不会更改XMM,因为它通过其他位置,寄存器或堆栈传递int0
  • 第二个printf()最终从XMM寄存器中获取格式double的{​​{1}}值,其中%f之前已存储过1.5。因此输出1.500000

以上都不能以任何方式得到保证,但这可能是您感兴趣的解释。不同的系统可能以不同的方式处理参数传递,它们是ABI(应用程序二进制接口)的一部分。

只是为了好玩,您可能想尝试这种变化:

printf("first %d, second %f\n", 1.5, 42);

在我的系统上输出first 42, second 1.500000

答案 1 :(得分:7)

你有一些undefined behavior(所以任意不好的事情可以happen,你不应该期待任何好事。使用%f时,printf函数需要double(请注意,当作为参数传递时,float会被提升为double,但0是类型为int的文字。此外,不同的编译器(甚至是同一编译器的不同版本)或不同的优化标志会产生不同的不良影响。

请在What Every C programmer should know about undefined behavior上阅读Lattner的博客。

(对未定义行为的良好态度是尽力避免它;不要浪费时间去理解具体发生的事情;但要把UB视为非常或者你总是避免的“生病

要解释观察到的行为,您需要深入了解特定实现的细节,特别是ABIcalling conventions(对于可变函数àlaprintf)。另外,查看生成的汇编程序代码(使用GCC,使用gcc -fverbose-asm -S -O1进行编译);有可能在一个寄存器(或某个call stack槽)中传递了一个不同于int参数的双参数(因此printf函数正在使垃圾发生在那里地点或登记);另请注意,sizeof(int)通常可能为4,但sizeof(double)可能为8(因此数据量甚至不正确)。

为避免此类错误,请习惯使用良好的编译器(例如GCC域中的Clang/LLVMfree software)进行编译,并启用所有警告和调试信息(例如编译)将gcc -Wall -Wextra -gGCC一起使用。编译器会警告你。

BTW,void main()是非法的。它应该至少为int main(void),最好是int main(int argc, char**argv),你应该注意这些论点。

通过您的示例,gcc -Wall -Wextra(使用GCC 7)告诉(对于您的源文件april.c):

april.c:4:10: warning: return type of ‘main’ is not ‘int’ [-Wmain]
     void main() {
          ^~~~
april.c: In function ‘main’:
april.c:5:14: warning: format ‘%d’ expects argument of type ‘int’,
                       but argument 2 has type ‘double’ [-Wformat=]
     printf("%d\n", 1.5);
             ~^
             %f
april.c:6:14: warning: format ‘%f’ expects argument of type ‘double’, 
                       but argument 2 has type ‘int’ [-Wformat=]
     printf("%f", 0);
             ~^
             %d

注意:Dev-C++CodeBlocks 不是编译器,但是IDE s。他们都在您的系统上运行了一些外部 compiler(可能GCCMinGW