[英]Why is this code printing 0?
void main()
{
clrscr();
float f = 3.3;
/* In printf() I intentionaly put %d format specifier to see
what type of output I may get */
printf("value of variable a is: %d", f);
getch();
}
实际上, %d
告诉printf
在某个位置查找整数参数。 但是你传递了一个float
参数,它被放在不同的地方。 C 标准没有指定执行此操作时会发生什么。 在这种情况下,可能在printf
寻找整数参数的地方有一个零,所以它打印了“0”。 在其他情况下,可能会发生不同的事情。
对printf
使用无效的格式说明符会调用未定义的行为。 这在C 标准的第 7.21.6.1p9 节中指定:
如果转换规范无效,则行为未定义。282) 如果任何参数不是相应转换规范的正确类型,则行为未定义。
这意味着您无法可靠地预测程序的输出结果。 例如,我系统上的相同代码打印 -1554224520 作为值。
至于最有可能发生的情况, %d
格式说明符正在寻找一个int
作为参数。 假设一个int
被堆栈和一个通过int
是4个字节长,则printf
功能着眼于堆栈中给出的值上的下一个4个字节。 许多实现不会在堆栈上传递浮点值,而是在寄存器中传递,因此它会看到碰巧在那里的任何垃圾值。 即使在堆栈上传递float
, float
和int
具有非常不同的表示形式,因此将float
的字节打印为int
很可能不会为您提供相同的值。
让我们看一个不同的例子。 假设我写
#include <string.h>
char buf[10];
float f = 3.3;
memset(buf, 'x', f);
memset
的第三个参数应该是一个整数(实际上是一个size_t
类型的值),告诉memset
要将多少个buf
字符设置为'x'
。 但是我传递了一个float
值。 发生什么了? 好吧,编译器知道第三个参数应该是一个整数,所以它会自动执行适当的转换,代码最终将buf
的前三个(三个点零)字符设置为'x'
。
(重要的是,编译器知道memset
的第三个参数应该是整数的方式是基于memset
的原型函数声明,它是头文件<string.h>
。)
现在,当你打电话
printf("value of variable f is: %d", f);
你可能认为同样的事情会发生。 您传递了一个float
,但%d
需要一个int
,因此会发生自动转换,对吗?
错误的。 让我再说一遍:错了。
也许令人惊讶的事实是, printf
是不同的。 printf
很特别。 编译器不一定知道传递给printf
的参数的正确类型应该是什么,因为这取决于隐藏在格式字符串中的%
说明符的详细信息。 所以没有自动转换到正确的类型。 您的工作是确保您实际传递的参数类型完全适合格式说明符。 如果它们不匹配,编译器不会自动执行相应的转换。 如果它们不匹配,就会发生疯狂的错误结果。
( printf
的原型函数声明是什么样的?字面上看起来像这样: extern int printf(const char *, ...);
。这三个点...
表示可变长度参数列表或“varargs”,它们告诉编译器它不知道还有多少参数,或者它们的类型应该是什么。所以编译器执行一些基本的转换——比如将类型char
和short int
上转换为int
,并将float
为double
——然后就这样了。)
我说“编译器不一定知道传递给printf
的参数的正确类型应该是什么”,但是现在,好的编译器会加倍努力并尝试弄清楚,如果可以的话。 他们仍然不会执行自动转换(根据语言规则,他们实际上不被允许这样做),但他们至少可以警告您。 例如,我在两个不同的编译器下尝试了您的代码。 两者都说了一些warning: format specifies type 'int' but the argument has type 'float'
。 如果您的编译器没有给您这样的警告,我鼓励您查明是否可以启用这些警告,或者考虑切换到更好的编译器。
尝试
printf("... %f",f);
这就是您打印浮点数的方式。 也许您只想打印f 的x 位数字,例如:
printf("... %.3f" f);
这将在点后打印 3 位数字的浮点数。 请通读此列表:
%c - 字符
%d 或 %i - 有符号十进制整数
%e - 使用 e 字符的科学记数法(尾数/指数)
%E - 使用 E 字符的科学记数法(尾数/指数)
%f - 十进制浮点数
%g - 使用 %e 或 %f 中的较短者
%G - 使用 %E 或 %f 中的较短者
%o - 有符号八进制
%s - 字符串
%u - 无符号十进制整数
%x - 无符号十六进制整数
%X - 无符号十六进制整数(大写字母)
%p - 指针地址
%n - 未打印任何内容
代码打印 0,因为您使用的是格式标记 %d,它表示有符号十进制整数 ( http://devdocs.io )。
你能试试吗
void main() {
clrscr();
float f=3.3;
/* In printf() I intentionaly put %d format specifier to see what type of output I may get */
printf("value of variable a is: %f",f);
getch();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.