这是什么问题以及如何解决

时间:2018-11-05 19:06:38

标签: c

int main(void)
{
    int a = 65;

char c = (char)a;
    int m = 3.0/2;

    printf("%c\n", c);              // output: A
    //printf("this %f\n", 5 / 2); //0.000000
    printf("%f\n", (float)a);       // output: 65.000000
    printf("this %f\n", 5 / 2);   //65.0000
    printf("%f\n", 5.0 / 2);        // output: 2.5000000
    //printf("this %f\n", 5 / 2);      2.500
    printf("%f\n", 5 / 2.0);        // output: 2.5000000
    //printf("this %f\n", 5 / 2); 2.5000
    printf("%f\n", (float)5 / 2);   // output: 2.5000000
    //printf("this %f\n", 5 / 2); 2.500
    printf("%f\n", 5 / (float)2);   // output: 2.5000000
    //printf("this %f\n", 5 / 2); 2.5000
    printf("%f\n", (float)(5 / 2)); // output: 2.0000000 - we cast only after division and result was 2
    //printf("this %f\n", 5 / 2); 2.0000000
    printf("%f\n", 5.0 / 2);        // output: 2.5000000
    //printf("this %f\n", 5 / 2); 2.500
    printf("%d\n", m);              // output: 1
    //printf("this %f\n", 5 / 2); 2.500

    system("PAUSE");
    return 0;
}

为什么每个注释中编写的所有内容都会更改,为什么每个注释中都会发生此更改? 例如,在第一条评论中,为什么会发生这种情况以及如何解决它的原因是0.00

2 个答案:

答案 0 :(得分:1)

问题是您通过使用错误的格式说明符来调用未定义的行为。 5/2的类型为2的值为int,但是您使用%f进行打印。您应该将5/2更改为5.0/2,使其类型为double或使用%d打印。

printf("this %f\n", 5.0/ 2);

printf("this %d\n", 5 / 2);

答案 1 :(得分:1)

要扩大对Osiris的回答...

printf是所谓的 variadic 函数-它具有可变数量的参数。函数原型如下:

int printf( const char * restrict format, ... );

这意味着该函数接受一个固定参数(format),然后接受一些未知数(零个或多个)的附加参数。现在,这就是问题所在– printf知道还有其他参数的唯一方法是它们的类型取决于您在format字符串中指定的内容。 printf不知道-它不知道-您在参数列表中实际传递了什么。它仅根据您在格式字符串中使用的转换说明符知道您的 claim 在参数列表中。

如果你写

 printf( "%f\n", 1.0, 2, "3", '4', 5.0 );

那么就printf而言,您仅传递了一个附加的double自变量1.0。即使您在格式字符串后传递了5个参数,printf仍会查看单个%f并得出结论,只有一个附加参数。请注意,这种特殊情况是定义明确的-将评估其他参数,但否则将忽略。从这里的代码行为是可预测的意义上来说,这是“安全的”。

如果你写

printf( "%f\n" );

然后您就遇到了问题,因为printf假设还有一个额外的double参数,它将继续寻找它(在寄存器中或堆栈中,取决于调用约定)。在这种情况下,行为是 undefined -最终结果可以是任何东西,从垃圾输出到彻底崩溃。

如果你写

printf( "%f\n", 5 / 2 ); // int / int == int 

您有两个问题之一。如果函数参数是通过寄存器传递的,则您会遇到与上述相同的问题(整数参数通常在与浮点参数不同的一组寄存器中传递,因此printf将在错误的寄存器中查找)。如果函数参数是通过堆栈传递的,则printf将抢占堆栈中的下一个sizeof (double)字节,并将其解释为double。在这种情况下,问题在于intdouble的表示可能根本不同。在32位int中,2通常表示为0x00000002。在64位double(假设使用IEEE-754表示)中,2.0表示为0x4000000000000000。同样,此行为是 undefined -您不能相信得到的任何结果。