Ter*_*nal 3 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);
}
Run Code Online (Sandbox Code Playgroud)
看了一眼,我认为它是标准中引用的一些未定义的输出:
警告:printf使用其第一个参数来决定跟随的参数数量以及它们的类型.它会变得混乱,如果没有足够的参数,如果它们是错误的类型,你会得到错误的答案.
但是输出结果并没有让我离开这个问题而不给它第二个想法.
(给出的输入是23).
23
0
23.000000
23.000000
23.000000
23.000000
23.000000
Run Code Online (Sandbox Code Playgroud)
为什么总是23.00000?编译器实际上在这里尝试做什么?而不是弄乱存储的值x,为什么它打印的值t?它是否有任何解释,因为似乎有一些关于这个未定义的输出(双关语)的定义.
我在32位机器上使用gcc编译器.
Cub*_*bbi 10
程序行为未定义,允许编译器执行任何操作.
也就是说,我能够在我的系统上重现这种行为,只需看一下装配输出就会发生什么:
printf("%d\n",t);首先将浮点值加载t到CPU寄存器中%xmm0,该寄存器在我的平台上用于将浮点参数传递给函数.该调用不会访问该寄存器printf(),因为它正在寻找整数输入.
由于您没有将任何浮点值传递给printf或任何其他函数,因此后续调用printf()任何值%xmm0都没有加载.但是当每个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
Run Code Online (Sandbox Code Playgroud)