C代码输出说明

发布于 2024-11-24 07:51:09 字数 805 浏览 0 评论 0原文

我遇到了这段代码:

#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);
}  

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

警告:printf 使用其第一个参数来决定有多少个参数 关注以及他们的类型是什么。它会变得混乱,你会得到 错误的答案,如果没有足够的论据,如果它们是 类型错误。

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

23 
0
23.000000
23.000000
23.000000
23.000000
23.000000

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

编辑:

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

I came across this code:

#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);
}  

Glancing at it I thought of it as some undefined output as quoted in standards:

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.

But the output didn't let me leave this question without giving it second thought.
(input given is 23).

23 
0
23.000000
23.000000
23.000000
23.000000
23.000000

Why always 23.00000? What is the compiler actually trying to do here? Instead of messing around with the value stored at x, why does it print the value of t? Does it have any explanation, because there seems something defined about this undefined output (pun intended).

Edit:

I am using gcc compiler on 32 bit machine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半衬遮猫 2024-12-01 07:51:09

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

也就是说,我能够在我的系统上重现此行为,并且浏览一下程序集输出即可了解发生的情况:

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

The program behavior is undefined, the compiler is permitted to do anything at all.

That said, I am able to reproduce this behavior on my system and a glance at the assembly output shows what happens:

printf("%d\n",t); begins by loading the floating point value from t into the CPU register %xmm0 which is used on my platform to pass floating-point arguments to functions. That register is not accessed by this call to printf(), since it is looking for an integer input instead.

None of the subsequent calls to printf() load any values into %xmm0, since you're not passing any floating-point values into printf or into any other function. But when each printf encounters %f in its format string, it reads from %xmm0, which still contains 23.0

Assembly output, from CLang, using a simpler program with 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
莳間冲淡了誓言ζ 2024-12-01 07:51:09

如果您确实想知道是什么产生了这里的行为,您需要查看此(完全损坏的)C 代码正在为您的特定编译器和 CPU 翻译成的汇编代码。

If you really want to know what is producing the behavior here, you need to look at the assembly code this (completely broken) C code is being translated to for your particular compiler and CPU.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文