C 为什么第一个和第三个printf的工作方式如此不同?

C 为什么第一个和第三个printf的工作方式如此不同?,c,printf,C,Printf,虽然first和last printf语句完全相同,但它们的输出不同。为什么? 因为一个int在printf需要float时被传递给printf,这就是它工作异常的原因。但我的观点是,为什么在最后一个print语句中,它没有打印一些垃圾值或0,而是使用第二个printf语句的值,这就是被打印的内容 因为您的程序调用了未定义的行为。98属于int类型,但%f需要一个浮点值(或双精度,由于默认的升级规则) 因此,由于当转换说明符的类型与实际类型不匹配时,printf()会有UB,因此没有合理的解释说

虽然first和last printf语句完全相同,但它们的输出不同。为什么?


因为一个int在printf需要float时被传递给printf,这就是它工作异常的原因。但我的观点是,为什么在最后一个print语句中,它没有打印一些垃圾值或0,而是使用第二个printf语句的值,这就是被打印的内容

因为您的程序调用了未定义的行为。
98
属于
int
类型,但
%f
需要一个
浮点值(或
双精度
,由于默认的升级规则)


因此,由于当转换说明符的类型与实际类型不匹配时,
printf()
会有UB,因此没有合理的解释说明它会有什么作用。

这是因为
%f
需要一个双参数。给出
int
是未定义的行为

§7.19.6.1,9

如果任何参数不是相应转换规范的正确类型,则行为未定义

指行为不可预测的计算机代码

至少在gcc中,如果启用了警告,您将得到相应的警告:

警告:格式“%f”要求类型为“double”,但参数2的类型为“int”


%f
需要
双精度
,但您正在传递一个
int
值。这是未定义的行为

适当的做法是:

printf("line 5: %f\n",98);  //output is 0.000000
printf("line 6: %f\n",98.98); //output is 98.980000  
printf("line 5: %f\n",98);//though same as first printf statement but output is 98.979980

如果我们查看编译器生成的代码,我们会看到以下内容:

printf("line 5: %f\n",98.0); 
printf("line 6: %f\n",98.98); 
printf("line 5: %f\n",98.0);

正如其他人已经说过的,当它期望一个
double
时,将
int
传递给
printf
会导致未定义的行为,任何事情都可能发生。您可能对程序在第三行打印
98.979980
而不是一些随机数的原因感兴趣

参数被传递到堆栈上的
printf
。当第2行通过
98.98
printf
时,它被推到堆栈上,数字的最低有效部分排在第一位

然后
printf
返回,在第三行再次调用它,现在在堆栈上按下
98
。在您的架构上,
int
类型似乎是32位;只有
double
类型大小的一半,因此这只覆盖先前堆栈上的
98.98
的下半部分。98.98的上半部分仍在堆栈上

现在,对
printf
的第三个调用从堆栈中读取一个
double
。它读取的内容中最重要的一半来自于早期堆栈上的
98.98
,而不太重要的一半来自于
98
的二进制表示;这就是为什么结果如此接近
98.98
。由于98是一个非常小的数字,它的最高有效位将是0,而将
98.98
的最低有效位设置为0,则会得到一个较小的数字

如果第3行使用了一个将更多位设置为1的数字,则得到的结果将超过
98.98
。例如,-1的二进制表示将其所有位设置为1,您可以得到:

printf("line 5: %f\n",(float)98);  //output is 98.000000
printf("line 6: %f\n",98.98); //output is 98.980000  
printf("line 5: %f\n",(float)98); //output is 98.000000

如果编译器使用64位整数,或先传递最重要部分的双精度整数,或使用寄存器而不是堆栈来传递参数,则会得到非常不同的结果。

@hbrock,编译器并不重要。OP的代码导致未定义的行为。这个问题重复了数百次。因为int在printf期望浮点时被传递给printf,这就是它工作异常的原因。但我的观点是,为什么在最后一个print语句中,它没有打印一些垃圾值或0,而是使用第二个printf语句的值,这就是被打印的内容。
printf("line 5: %f\n",(float)98);  //output is 98.000000
printf("line 6: %f\n",98.98); //output is 98.980000  
printf("line 5: %f\n",(float)98); //output is 98.000000
printf("line 2: %f\n", 98.98); # 98.98
printf("line 3: %f\n", -1);    # 98.980042