int main(void)
{
int a = 65;
char c = (char)a;
printf("%c\n", c); // output: A
printf("%f\n", (float)a); // output: 65.000000
printf("%f\n", 5/2); // output: 65.000000 why???
return 0;
}
//why printf("%f\n", 5/2); prints same number as a number above????
它应该打印2.5,我想知道为什么它不打印这个数字,会发生什么? 我试图在Google上找到答案,但是我不确定如何质疑这个问题
答案 0 :(得分:3)
该代码中包含UB。在第三个printf中-您传递整数,但printf需要双精度-UB
广播它,它将正常工作 https://godbolt.org/z/M3ysha
答案 1 :(得分:2)
这是一个简化且不一定完全正确的答案,但是:当您在%f
格式的语句中使用printf
时,不是的意思是“采用下一个参数”已通过,然后将其打印为浮动”。不,相反,它的意思是“获取传递的下一个float参数,然后打印它”。但是在您的第三个printf
调用中,没有传递 (因为5/2
给出了int
的值为2)。因此,当printf
转到传递浮点参数的位置时,即使它是由先前的printf
调用传递的,它还是偶然会获得您传递的最后一个实际浮点数。
并不能保证会发生这种情况,显然这不是您想要依靠的事情,但这可以解释您看到自己看到的东西的原因。
好的编译器会在printf
参数的数量或类型与格式字符串不匹配时警告您,从而避免了这种错误。例如,我说
warning: format specifies type 'double' but the argument has type 'int'
如果您的编译器不知道如何打印此类警告,则您可能希望尝试找到更好的警告。
答案 2 :(得分:0)
5和2是整数,5/2也是整数,并被截断为下一个int 2
尝试投射(double)(5/2)
或使用5.0 / 2.0
答案 3 :(得分:0)
5 / 2
计算为整数:5/2->2。ptinf()
期望有%f
。printf
会打印出来。为了证明这一点,我们可以使用更大的数字,例如5000/3。您应该正确地转换数据,或使用正确的文字5.0代替5。
#include <stdio.h>
int main(void)
{
printf("5/3 d:\t\t\t %d\n", 5/3);
// printf("5/3 n:\t\t\t %n\n", 5/3); // segfault
printf("5/3 f:\t\t\t %f\n", 5/3);
printf("(double) 5/3 d:\t\t %d \n", (double) 5/3);
// printf("(double) 5/3 n:\t\t %n \n", (double) 5/3); // memory corruption
printf("(double) 5/3 f:\t\t %f \n", (double) 5/3);
printf("(float) 5/3 d:\t\t %d \n", (float) 5/3);
// printf("(float) 5/3 n:\t\t %n \n", (float) 5/3); // memory corruption
printf("(float) 5/3 f:\t\t %f \n", (float) 5/3);
printf("5/3 d:\t\t\t %d \n", 5000/3);
// printf("5/3 n:\t\t\t %n \n", 5000/3); // segfault
printf("5/3 f:\t\t\t %f \n", 5000/3);
printf("5./3. d:\t\t %d \n", 5./3.);
// printf("5./3. n:\t\t %n \n", 5./3.); // memory corruption
printf("5./3. f:\t\t %f \n", 5./3.);
return 0;
}
输出:
5/3 d: 1
5/3 f: 0.000000
(double) 5/3 d: 33989216
(double) 5/3 f: 1.666667
(float) 5/3 d: 33989216
(float) 5/3 f: 1.666667
5/3 d: 1666
5/3 f: 1.666667
5./3. d: 33989216
5./3. f: 1.666667
因此,无论是5/2还是其他值,重要的是数据类型。就您而言,强制转换链:(float) (int) 5/2 = 1
恰好等于30.0000 float。
另外,将2或4个字节的整数输入到printf中,并告诉它期望8个字节(例如,传递int和格式化为double的形式),希望您会遇到段错误,如果您不够幸运的话,将获得内存腐败和难以跟踪的错误。
答案 4 :(得分:0)
该行为是由于参数传递给函数的方式引起的。
例如,整数值通过诸如edx,esi等寄存器传递(只要参数适合可用寄存器)。但是,浮点参数在xmm *寄存器中传递(只要它们适合可用的寄存器)。
因此,在函数内部,根据类型说明符从相应的寄存器中获取值。因此,%d
将从edx
/ esi
等中获取,而%f
将从xmm*
寄存器中获取。
在您的情况下,由于类型转换,第printf("%f\n", (float)a);
行将a
的值(为65)存储为实际值65.0
。结果,xxm0
寄存器的值将为65.0。
现在,当控件进入printf("%f\n", 5/2);
时,函数参数5/2
是一个整数。因此它不会被推送到xxm0
寄存器中。但是,由于%f
期望xxm*
(在这种情况下为xxm0
)寄存器中有一个值,因此它仅重试xxm0中存在的任何值。在您的情况下,xxm0
已存储了先前printf()
调用中的值65.0。这样就打印了65.0。
下面的程序应该使它更清楚:
int main(void)
{
printf("%f\n", 10, 11.1, 12.2, 40); // 11.100000
printf("%f %f\n", 5/2, 1, 2, 3, 4); // 11.100000 12.200000
}
在第一次printf()
,xxm0 = 11.1
和xxm1 = 12.2
通话期间。由于第二个printf()
中的所有参数均为整数,因此xxm*
寄存器中没有存储任何内容(这也意味着xxm*
寄存器的旧值保持不变)。由于%f
期望实数位于xxm*
寄存器中,因此它只打印它们持有的任何值(在这种情况下,是第一个printf()
语句中的值)。
您可以使用Headless Service查看生成的汇编代码。