c - C代码输出说明

标签 c undefined-behavior

我遇到了这段代码:

#include<stdio.h>
void main()
{
    int x;
    float t;
    scanf("%f",&t);
    printf("%d\n",t);
    x=90;
    printf("%f\n",x);
    {
        x=1;
        printf("%f\n",x);
        {
            x=30;
            printf("%f\n",x);
        }
        printf("%f\n",x);
    }
    printf("%f\n",x);
}  

看一眼我认为它是标准中引用的一些未定义的输出:

A warning: printf uses its first argument to decide how many arguments follow and what their type is. It will get confused, and you will get wrong answers, if there are not enough arguments of if they are the wrong type.

但输出并没有让我不假思索地离开这个问题。
(给定的输入是 23)。

23 
0
23.000000
23.000000
23.000000
23.000000
23.000000

为什么总是 23.00000?编译器实际上想在这里做什么?为什么它打印 t 的值,而不是乱用存储在 x 的值?它有任何解释吗,因为似乎对这个未定义的输出有一些定义(双关语意)。

编辑:

我在 32 位机器上使用 gcc 编译器。

最佳答案

程序行为未定义,编译器可以做任何事情。

就是说,我能够在我的系统上重现这种行为,并且看一眼汇编输出就知道发生了什么:

printf("%d\n",t); 首先将浮点值从 t 加载到 CPU 寄存器 %xmm0 在我的平台上用于将浮点参数传递给函数。调用 printf() 不会访问该寄存器,因为它正在寻找整数输入。

随后对 printf() 的调用都不会将任何值加载到 %xmm0 中,因为您没有将任何浮点值传递到 printf 或任何其他功能。但是当每个 printf 在其格式字符串中遇到 %f 时,它会从 %xmm0 读取,其中仍然包含 23.0

来自 CLang 的程序集输出,使用带有 float t = 23.0;

的更简单的程序
.LCPI0_0:
    .quad   4627167142146473984     # double 2.300000e+01
...
    movl    $.L.str, %edi          # .L.str is "%d\n"
    movsd   .LCPI0_0(%rip), %xmm0  # 23.0 stored in xmm0 here
    movb    $1, %al
    callq   printf                 # this printf will print %esi

    movl    $90, %esi              # 90 stored in %esi here
    movl    $.L.str1, %edi         # .L.str1 is "%f\n"
    xorb    %al, %al
    callq   printf                 # but this printf will print %xmm0

关于c - C代码输出说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6682250/

相关文章:

c - 如何定义和声明库代码使用的全局变量?

调用 C 中的特定线程

c++ - 未定义的行为和顺序点

c++ - 有符号整数溢出在 C++ 中仍然是未定义的行为吗?

c++ - 可以将不同的 GCC 方言联系在一起吗?

c - 如何在 Xcode 6 中将库添加到我的 C 项目

创建 BlockType 结构的单链表

c - 运行这个有点奇怪的 c 代码后出现意外的输出。谁能解释这是怎么发生的?

c - 符合C标准的方法来访问空指针地址?

c - 如何在 Eclipse IDE 上使用 Cygwin C 编译器获得正确的警告