繁体   English   中英

为什么这个代码打印0?

[英]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个字节。 许多实现不会在堆栈上传递浮点值,而是在寄存器中传递,因此它会看到碰巧在那里的任何垃圾值。 即使在堆栈上传递floatfloatint具有非常不同的表示形式,因此将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”,它们告诉编译器它不知道还有多少参数,或者它们的类型应该是什么。所以编译器执行一些基本的转换——比如将类型charshort int上转换为int ,并将floatdouble ——然后就这样了。)

我说“编译器不一定知道传递给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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM