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

Apr*_*son 5 c printf

我在玩C; 看一下这个:

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

void main() {
    printf("%d\n", 1.5);
    printf("%f", 0);
}
Run Code Online (Sandbox Code Playgroud)

我期待输出:

0
0.000000
Run Code Online (Sandbox Code Playgroud)

但它打印:

0
1.500000
Run Code Online (Sandbox Code Playgroud)

第一次printf()通过1.5第二次printf()吗?

PS:我知道(%d对于整数,%f浮标).正如我所提到的,我只是在搞乱代码.

PS2:我正在使用DevC++和Code :: Blocks.

chq*_*lie 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格式的值.因此输出.%f1.51.500000

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

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

printf("first %d, second %f\n", 1.5, 42);
Run Code Online (Sandbox Code Playgroud)

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


Bas*_*tch 7

你有一些未定义的行为(所以可能发生任意不好的事情,你不应该期待任何好事).随着对的printf函数期望(注意,当作为参数传递一个被晋升为一个),但是是文字型的.此外,不同的编译器(甚至同一编译器的不同版本)或不同的优化标志可能会产生不同的不良影响.%fdoublefloatdouble0int

请阅读Lattner的博客,了解What Every C程序员应该了解的未定义行为.

(对未定义行为的良好态度是努力总是避免它;不要浪费时间去试图理解具体发生的事情;但是将UB视为非常肮脏或" 生病 "的东西,你总是避免)

要解释观察到的行为,您需要深入了解特定实现的细节,特别是ABI调用约定(对于可变函数àla printf).另外,查看生成的汇编代码(使用GCC,编译gcc -fverbose-asm -S -O1); 有可能在一个不同于一个参数的寄存器(或一些调用堆栈槽)中传递一个double参数int(因此该printf函数正在使垃圾发生在该位置或寄存器中); 另请注意,通常sizeof(int)可能是4但sizeof(double)可能是8(因此数据量甚至不对).

为了避免这种错误,需要有良好的编译器(如编译的习惯GCC锵/ LLVM免费软件领域),并启用所有警告和调试信息(例如,编译使用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
Run Code Online (Sandbox Code Playgroud)

注:开发-C++代码块没有编译器,但IDE秒.它们都运行一些外部 编译器(可能是GCC作为系统上的MinGW).

  • @AprilJohnson:单词**undefined**是故意选择的.没有"可预期的"结果.不同的编译器/(版本/选项,不同的时间,不同的气候,不同的环境等)会产生不同的结果,包括格式化硬盘或鼻守护进程. (3认同)