我遇到了一个问题,可以概括如下:
#include <stdio.h>
int main()
{
float f=23.45;
printf("main: %fn", f);
t1(f);
/* the result would be
main:23.450001
t1:2.000000 */
}
void t1(float f)
{
printf("t1: %fn", f);
}
我现在知道奇怪的行为是由于缺少原型声明和参数因此被提升,(float->double?),我仍然不明白为什么结果是2.000000,所以谁能给一个更详细的解释?我使用的是ubuntu10.04 gcc4.4.3
您正在观察的行为特定于基于堆栈的参数传递。对于那些默认编译64位x86代码并且无法复制它的人,您可以尝试使用"gcc -m32"而不是"gcc"。
通过基于堆栈的参数传递,t1()
从堆栈中读取32位,而这32位恰好形成了浮点值2.0
。在调用现场,因为t1
没有原型,参数f
被提升为double
,并且它是一个写在堆栈上的double
(C99 6.5.2.2:6)如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并且类型为float的参数被提升为double。
t1
没有理由从堆栈中恢复预期值,因为它没有正确地读取与写入相同类型和宽度的堆栈
因为编译器不知道t1
接受的是浮点数,所以它将浮点数提升为双精度。在您的平台上,t1
将该双精度体的前四个字节解释为浮点数。
2.0表示为1 x 2^0,在二进制中是三个0字节后面跟着一个64(在x86-64上)。事实上,23.45作为双精度类型具有相同的前四个字节,0,0,0,64(后面是51,115,55,64)。因此,如果你取双精度23.45并将其前四个字节解释为浮点数,你得到2.0。
请记住,缺少原型意味着稍后将使用int参数声明函数,并进行适当的转换。所以,我假设如果你在t1的声明中用int替换float,你会得到23的结果。