GCC编译时分错误

时间:2010-06-03 04:34:46

标签: c gcc compiler-construction

有人可以解释这种行为吗?

test.c的:

#include <stdio.h>

int main(void)
{
    printf("%d, %d\n", (int) (300.6000/0.05000), (int) (300.65000/0.05000));
    printf("%f, %f\n", (300.6000/0.05000), (300.65000/0.05000));
    return 0;
}

$ gcc test.c

$ ./a.out
6012, 6012
6012.000000, 6013.000000

我检查了汇编代码,它将第一个printf的参数都设置为6012,所以它似乎是一个编译时错误。

4 个答案:

答案 0 :(得分:9)

运行

#include <stdio.h>

int main(void)
{
    printf("%d, %d\n", (int) (300.6000/0.05000), (int) (300.65000/0.05000));
    printf("%.20f %.20f\n", (300.6000/0.05000), (300.65000/0.05000));
    return 0;
}

它应该更清楚。第二个的值(在浮点除法之后,这不是精确的)是~6012.9999999999991,所以当你用(int)截断它时,gcc足够聪明,可以在编译时输入6012。

当您打印浮动时,printf默认将它们格式化为仅显示6位精度,这意味着第二个打印为6013.000000。

答案 1 :(得分:7)

打印时,

printf()会对浮点数进行舍入。如果你添加更多精度,你可以看到发生了什么:

$ cat gccfloat.c
#include <stdio.h>

int main(void)
{
    printf("%d, %d\n", (int) (300.6000/0.05000), (int) (300.65000/0.05000));
    printf("%.15f, %.15f\n", (300.6000/0.05000), (300.65000/0.05000));
    return 0;
}

$ ./gccfloat
6012, 6012
6012.000000000000000, 6012.999999999999091

答案 2 :(得分:1)

听起来像是一个舍入错误。正在计算300.65000/0.05000(浮点数),如6012.99999999。当作为int进行转换时,它会被截断为6012。当然这在编译器优化中都是预先计算的,所以最终的二进制文件只包含值6012,这就是你所看到的。

您在第二个陈述中看不到相同的原因是因为它是舍入以供printf显示,而不是截断,因为当你转向int时会发生什么。 (参见@John Kugelman的回答。)

答案 3 :(得分:0)

很明显,但没有人告诉过:两个师的结果都是自然数。 那么编译器在哪里出错了?也许。 而且我在MS VS 2015中也重现了同样的问题,所以看起来错误的编译器是2.而且我打赌一分钱,LLVM也做同样的事情。 也许编译器是对的? 回答这个问题不适合我,我只是注意到以下几点:看起来这是一个“带小数的文字除法”的隐式演员问题加倍。

下面的小测试表明,一个double的内容,从编译时分配的2个文字的除法结果,没有强制转换,是错误的。 如果先前将结果转换为浮点数,则结果将变为正确。

Action<int> 

此输出跟随MS-VS.2015:

#include <stdio.h>

int main(void)
{
    float fb = (300.65000 / 0.05000);
    float fa = (300.6000 / 0.05000);
    float fb1 = 6013.0;
    float fa1 = 6012.0;
    char bufffa[sizeof(float) * 2 +1] = { 0 };
    char bufffb[sizeof(float) * 2 +1] = { 0 };

    double db = (300.65000 / 0.05000);
    double da = (300.6000 / 0.05000);
    double db1 = 6013.0;
    double da1 = 6012.0;
    char buffda[sizeof(double) * 2 + 1] = { 0 };
    char buffdb[sizeof(double) * 2 + 1] = { 0 };
    int i;
    printf("sizeof(float)=%d, sizeof(double)=%d\n", sizeof(float), sizeof(double));
    for (i = 0; i < sizeof(fa); i++)
    {
        sprintf(bufffa + (i * 2), "%02X", ((unsigned char*)(&fa))[i]);
        sprintf(bufffb + (i * 2), "%02X", ((unsigned char*)(&fb))[i]);
    }
    printf("OK: float binary form (compile time division):     fa=%s, fb=%s\n", bufffa, bufffb);
    for (i = 0; i < sizeof(fa1); i++)
    {
        sprintf(bufffa + (i * 2), "%02X", ((unsigned char*)(&fa1))[i]);
        sprintf(bufffb + (i * 2), "%02X", ((unsigned char*)(&fb1))[i]);
    }
    printf("OK: float binary form (NOT compile time division): fa1=%s, fb1=%s\n", bufffa, bufffb);

    for (i = 0; i < sizeof(da); i++)
    {
        sprintf(buffda + (i * 2), "%02X", ((unsigned char*)(&da))[i]);
        sprintf(buffdb + (i * 2), "%02X", ((unsigned char*)(&db))[i]);
    }
    printf("NOT OK: double binary form (compile time division):    da=%s, db=%s\n", buffda, buffdb);

    for (i = 0; i < sizeof(da1); i++)
    {
        sprintf(buffda + (i * 2), "%02X", ((unsigned char*)(&da1))[i]);
        sprintf(buffdb + (i * 2), "%02X", ((unsigned char*)(&db1))[i]);
    }
    printf("OK: double binary form (NOT compile time division):da1=%s, db1=%s\n", buffda, buffdb);


    printf("incorrect values:\n");
    printf("printf(int) compile time division, literal: a=%d, b=%d\n", (int)(300.6000 / 0.05000), (int)(300.65000 / 0.05000));
    printf("printf(float) compile time division, literal: a=%.15f, b=%.15f\n", (300.6000 / 0.05000), (300.65000 / 0.05000));

    printf("printf(double) compile time division: da=%.15f, db=%.15f\n", da, db);

    printf("correct values:\n");
    printf("printf(int) compile time division, literal with cast: a=%d, b=%d\n", (int)(300.6000 / 0.05000), (int)(float)(300.65000 / 0.05000));
    printf("printf(float) compile time division, literal  with cast: a=%.15f, b=%.15f\n", (float)(300.6000 / 0.05000), (float)(300.65000 / 0.05000));
    printf("printf(float) compile time division: fa=%.15f, fb=%.15f\n", fa, fb);
    printf("printf(float) NOT compile time division: fa1=%.15f, fb1=%.15f\n", fa1, fb1);
    printf("printf(double) NOT compile time division: da1=%.15f, db1=%.15f\n", da1, db1);



    return 0;
}