为什么printf会打印最后一个数字?

Jul*_*Vga 4 c printf

编辑:我已经知道printf不是类型安全我只是在寻找一个关于究竟是什么发生的探索(我的意思是描述未定义的行为).

为什么我在第二个printf中打印"7",程序打印9.334354.我知道如果我不写7.0,这将不会被打印,但为什么要写第一个数字呢?

#include <stdio.h>  

int main()  
{  
    printf("%.2f\n", 9.334354);    
    printf("%.5f\n", 7);  
    printf("%03d\n", 9);  
    getchar();  
}
Run Code Online (Sandbox Code Playgroud)

这是输出

    9.33
    9.33435
    009
Run Code Online (Sandbox Code Playgroud)

Ker*_* SB 16

每晚睡前一次给自己重复两次:

printf不是类型安全的.printf不是类型安全的.printf不是类型安全的.

该函数仅在您传递了您承诺的类型的参数时才有效.其他一切都是未定义的行为.你保证double(通过%f)但提供int(文字的类型7),所以它是未定义的行为.你太无耻了.

(如果你感兴趣,我曾经详细解释实际输出.)


更新:由于您对此特定行为的解释感兴趣,因此这是我的x86/GCC4.6.2/-O3上该代码的(相关)程序集:

首先是数据部分:

.LC0:
        .long   1921946325
        .long   1076013872   // 0x 4022AB30 728E92D5 is the binary rep of 9.334354
.LC1:
        .string "%.2f\n"
.LC2:
        .string "%.5f\n"
.LC3:
        .string "%03d\n"
Run Code Online (Sandbox Code Playgroud)

现在的代码:

        fldl    .LC0              // load number into fp register
        fstpl   4(%esp)           // put 64-bit double on the stack
        movl    $.LC1, (%esp)     // first argument (format string)
        call    printf            // call printf

        movl    $7, 4(%esp)       // put integer VA (7) onto stack
        movl    $.LC2, (%esp)     // first argument (format string)
        call    printf            // call printf

        movl    $9, 4(%esp)       // put integer VA (9) onto stack
        movl    $.LC3, (%esp)     // first argument (format string)
        call    printf            // call printf
Run Code Online (Sandbox Code Playgroud)

你看到你所看到的东西的原因现在很简单.让我们暂时切换到完整的17位输出:

  printf("%.17f\n", 9.334354);
  printf("%.17f\n", 7);
Run Code Online (Sandbox Code Playgroud)

我们得到:

9.33435399999999937
9.33435058593751243
Run Code Online (Sandbox Code Playgroud)

现在让我们用"正确的"二进制组件替换整数:

 printf("%.17f\n", 9.334354);
 printf("%.17f\n", 1921946325);
Run Code Online (Sandbox Code Playgroud)

瞧:

9.33435399999999937
9.33435399999999937
Run Code Online (Sandbox Code Playgroud)

会发生什么是double占用堆栈上的8个字节的值0x4022AB30728E92D5.整数只占用4个字节,并且当发生时,最重要的四个字节被覆盖,因此浮点值仍然几乎相同.如果用原始浮点数中出现的相同字节覆盖四个字节,则得到完全相同的结果.

我可能会补充说,纯粹的运气是最重要的四个字节保持不变.在不同的情况下,它们可能已被其他东西覆盖.简而言之,"未定义的行为".

  • "我只是在寻找一种探索" - 为什么?这样的解释对你没有好处......这里没有人可以给你,因为它是你的C系统实现的工件."它可能会......" - 不,可能不是. (3认同)