在C中缺少原型声明时,由于参数提升而导致的奇怪结果



我遇到了一个问题,可以概括如下:

#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的结果。

最新更新