[英]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????
it supposed to print 2.5, i want to know why it doesn't prints this number and what's happens bts?它应该打印 2.5,我想知道为什么它不打印这个数字以及 bts 会发生什么? i tried to find answers on google but i'm not sure how to question this problem
我试图在谷歌上找到答案,但我不知道如何质疑这个问题
you have the UB in that code.你在那个代码中有 UB。 in the third printf - you pass integer but printf expects double - UB
在第三个 printf 中 - 你传递整数但 printf 期望双倍 - UB
cast it and it will work correctly https://godbolt.org/z/M3ysha投它,它会正常工作https://godbolt.org/z/M3ysha
This is a simplified and not necessarily perfectly accurate answer, but: When you use %f
in a printf
format statement, it does not mean "take the next argument that was passed, and print it as a float".这是一个简单而不一定是完全准确的答案,但是:当您使用
%f
在printf
格式声明,这并不意味着“采取传递的一个参数,并将其打印为浮动”。 No, instead what it means is "take the next float argument that was passed, and print it."不,它的意思是“获取传递的下一个浮点参数,并打印它”。 But in your third
printf
call, there was no float argument that was passed (because 5/2
gives the int
value 2).但是,在你的第三个
printf
电话,有这是没有通过float参数(因为5/2
给int
值2)。 So when printf
went to look in the place where float arguments are passed, by chance it picked up the last actual floating-point number you had passed, even though it was passed by the previous printf
call.因此,当
printf
去查看传递浮点参数的地方时,它偶然地选择了您传递的最后一个实际浮点数,即使它是由前一个printf
调用传递的。
This is not guaranteed to happen, and obviously it's not the sort of thing you'd want to depend on, but it explains why you saw what you saw.这不能保证会发生,显然这不是你想要依赖的那种事情,但它解释了为什么你看到了你所看到的。
Good compilers help you avoid this kind of mistake by warning you when the number or type of your printf
arguments do not match the format string.好的编译器会在
printf
参数的数量或类型与格式字符串不匹配时发出警告,从而帮助您避免这种错误。 For example, mine says例如,我的说
warning: format specifies type 'double' but the argument has type 'int'
If your compiler doesn't know how to print warnings like these, you might like to try to find a better one.如果您的编译器不知道如何打印这些警告,您可能想尝试找到一个更好的。
5 and 2 are integers, 5/2 is a integer too and truncated to the next int which is 2 5 和 2 是整数,5/2 也是整数并被截断到下一个整数,即 2
try to cast (double)(5/2)尝试投(双)(5/2)
or use 5.0 / 2.0或使用 5.0 / 2.0
5 / 2
as an integer: 5 / 2 -> 2. 5 / 2
计算为整数:5 / 2 -> 2。ptinf()
is expecting a %f
. ptinf()
期待一个%f
。printf
loyally prints.printf
忠实地打印出来。 To demonstrate this we can use a bigger number, 5000 / 3 for instance.为了证明这一点,我们可以使用更大的数字,例如 5000 / 3。 You should properly cast your data, or use the proper literals 5.0 instead of 5.
您应该正确地转换数据,或使用正确的文字 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;
}
output:输出:
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
So, it doesn't matter if it's 5/2 or something else, what matters is the data type.所以,不管是 5/2 还是其他什么,重要的是数据类型。 In your case, the chain of casts:
(float) (int) 5/2 = 1
accidentally happens to be equals to 30.0000 float.在您的情况下,转换链:
(float) (int) 5/2 = 1
意外地等于 30.0000 float。
Also, feeding 2 or 4 bytes integer into printf and telling it to expect 8 bytes (such as passing int and formatting as double), hopefully you'll get a segfault, if you're unlucky enough you'll get memory corruption and hard to track bugs.此外,将 2 或 4 个字节的整数输入 printf 并告诉它期望 8 个字节(例如传递 int 和格式化为 double),希望你会得到段错误,如果你足够不幸,你会得到内存损坏和困难跟踪错误。
The behaviour is due to the way arguments are passed to functions.这种行为是由于参数传递给函数的方式造成的。
For eg, integer values are passed via registers like edx, esi etc. (as long as the arguments fit in available registers).例如,整数值通过 edx、esi 等寄存器传递(只要参数适合可用寄存器)。 However, floating point arguments are passed in xmm* registers (as long as they fit in available registers).
但是,浮点参数在 xmm* 寄存器中传递(只要它们适合可用的寄存器)。
So inside the function, the values are fetched from appropriate registers based on the type specifier.因此,在函数内部,根据类型说明符从适当的寄存器中获取值。 So a
%d
would fetch from edx
/ esi
etc, and %f
would fetch from xmm*
registers.因此
%d
将从edx
/ esi
等中获取,而%f
将从xmm*
寄存器中获取。
In your case, the line printf("%f\\n", (float)a);
在您的情况下,该行
printf("%f\\n", (float)a);
stored the value of a
(which is 65) as a real value 65.0
due to typecasting.由于类型转换,将
a
的值(即 65)存储为实际值65.0
。 As a result, xxm0
register will have value 65.0.因此,
xxm0
寄存器的值为 65.0。
Now when the control came to printf("%f\\n", 5/2);
现在当控制来到
printf("%f\\n", 5/2);
, the function argument 5/2
is an integer. ,函数参数
5/2
是一个整数。 So it doesn't get pushed into xxm0
register.所以它不会被推入
xxm0
寄存器。 However since %f
expects a value in xxm*
(in this case xxm0
) register, it just retries whatever value is there in xxm0.但是,由于
%f
期望xxm*
(在本例中为xxm0
)寄存器中的值,因此它只会重试 xxm0 中的任何值。 In your case, xxm0
had stored the value 65.0 from earlier printf()
call.在您的情况下,
xxm0
已存储来自早期printf()
调用的值 65.0 。 So 65.0 is printed.所以 65.0 被打印出来。
The below program should make it more clear:下面的程序应该更清楚:
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
}
During first printf()
call, xxm0 = 11.1
and xxm1 = 12.2
.在第一次
printf()
调用期间, xxm0 = 11.1
和xxm1 = 12.2
。 Since all of the arguments in the second printf()
evaluate to be integers, so nothing gets stored in xxm*
registers (which also means old values of xxm*
registers remain unaltered).由于第二个
printf()
中的所有参数都计算为整数,因此xxm*
寄存器中不会存储任何内容(这也意味着xxm*
寄存器的旧值保持不变)。 Since %f
expects real numbers to be in xxm*
registers, it just prints whatever values they hold (in this case values from first printf()
statement).由于
%f
期望实数在xxm*
寄存器中,因此它只打印它们保存的任何值(在这种情况下,来自第一个printf()
语句的值)。
You can use https://www.godbolt.org to see the generated assembly code.您可以使用https://www.godbolt.org查看生成的汇编代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.