[英]why printf prints same value as the value above it?
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,我想知道为什么它不打印这个数字以及 bts 会发生什么? 我试图在谷歌上找到答案,但我不知道如何质疑这个问题
你在那个代码中有 UB。 在第三个 printf 中 - 你传递整数但 printf 期望双倍 - UB
投它,它会正常工作https://godbolt.org/z/M3ysha
这是一个简单而不一定是完全准确的答案,但是:当您使用%f
在printf
格式声明,这并不意味着“采取传递的一个参数,并将其打印为浮动”。 不,它的意思是“获取传递的下一个浮点参数,并打印它”。 但是,在你的第三个printf
电话,有这是没有通过float参数(因为5/2
给int
值2)。 因此,当printf
去查看传递浮点参数的地方时,它偶然地选择了您传递的最后一个实际浮点数,即使它是由前一个printf
调用传递的。
这不能保证会发生,显然这不是你想要依赖的那种事情,但它解释了为什么你看到了你所看到的。
好的编译器会在printf
参数的数量或类型与格式字符串不匹配时发出警告,从而帮助您避免这种错误。 例如,我的说
warning: format specifies type 'double' but the argument has type 'int'
如果您的编译器不知道如何打印这些警告,您可能想尝试找到一个更好的。
5 和 2 是整数,5/2 也是整数并被截断到下一个整数,即 2
尝试投(双)(5/2)
或使用 5.0 / 2.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),希望你会得到段错误,如果你足够不幸,你会得到内存损坏和困难跟踪错误。
这种行为是由于参数传递给函数的方式造成的。
例如,整数值通过 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()
语句的值)。
您可以使用https://www.godbolt.org查看生成的汇编代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.