如何在printf中处理float/double到int的转换?

San*_*dip 10 c

考虑这个计划

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传递时,所有小于intget的类型都会被提升int.所以在你的情况下,'d'正在升级为a int,然后printf弹出int并转换为a char.我可以找到这种行为的最佳参考是这篇博客文章.

  • 好答案.此行为不是特定于printf,而是适用于所有可变参数函数.va_arg联机帮助页有很好的记录,包括将字符提升为int.例如,您可以在http://stackoverflow.com/questions/1688942中查看我的答案 (2认同)

AnT*_*AnT 8

没有" int投入printf" 这样的东西.printf不做也不能做任何铸造.格式说明符不一致会导致未定义的行为.

实际上,printf只需接收原始数据并将其重新解释为格式说明符隐含的类型.如果你传递一个double值并指定一个int格式说明符(如%d),printf将取该double值并盲目地将其重新解释为a int.结果将是完全不可预测的(这就是为什么这样做正式导致C中的未定义行为).