考虑这个计划
int main()
{
float f = 11.22;
double d = 44.55;
int i,j;
i = f; //cast float to int
j = d; //cast double to int
printf("i = %d, j = %d, f = %d, d = %d", i,j,f,d);
//This prints the following:
// i = 11, j = 44, f = -536870912, d = 1076261027
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么从double/float到int的转换在第一种情况下正常工作,并且在printf中完成时不起作用?
该程序是在32位linux机器上的gcc-4.1.2上编译的.
编辑: Zach的答案似乎是合乎逻辑的,即使用格式说明符来确定从堆栈弹出的内容.但是请考虑这个后续问题:
int main()
{
char c = 'd'; // sizeof c is 1, however sizeof character literal
// 'd' is equal to sizeof(int) in ANSI C
printf("lit = %c, lit = %d , c = %c, c = %d", 'd', 'd', c, c);
//this prints: lit = d, lit = 100 , c = d, c = 100
//how does printf here pop off the right number of bytes even when
//the size represented by format specifiers doesn't actually match
//the size of the passed arguments(char(1 byte) & char_literal(4 bytes))
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是如何运作的?
Zac*_*sch 19
该printf
函数使用格式说明符来确定从堆栈弹出的内容.因此,当它看到时%d
,它弹出4个字节并将它们解释为a int
,这是错误的(二进制表示(float)3.0
不同(int)3
).
您需要使用%f
格式说明符或将参数转换为int
.如果您使用的是足够新的版本gcc
,则启用更强的警告可以捕获此类错误:
$ gcc -Wall -Werror test.c
cc1: warnings being treated as errors
test.c: In function ‘main’:
test.c:10: error: implicit declaration of function ‘printf’
test.c:10: error: incompatible implicit declaration of built-in function ‘printf’
test.c:10: error: format ‘%d’ expects type ‘int’, but argument 4 has type ‘double’
test.c:10: error: format ‘%d’ expects type ‘int’, but argument 5 has type ‘double’
Run Code Online (Sandbox Code Playgroud)
回答问题的编辑部分:
C的整数提升规则表示,当作为vararg传递时,所有小于int
get的类型都会被提升int
.所以在你的情况下,'d'
正在升级为a int
,然后printf弹出int
并转换为a char
.我可以找到这种行为的最佳参考是这篇博客文章.
没有" int
投入printf
" 这样的东西.printf
不做也不能做任何铸造.格式说明符不一致会导致未定义的行为.
实际上,printf
只需接收原始数据并将其重新解释为格式说明符隐含的类型.如果你传递一个double
值并指定一个int
格式说明符(如%d
),printf
将取该double
值并盲目地将其重新解释为a int
.结果将是完全不可预测的(这就是为什么这样做正式导致C中的未定义行为).