printf如何处理转换

时间:2015-12-19 22:24:06

标签: c

我正在阅读C programming: a modern approach的第7章,并且有点不清楚printf如何处理类型转换。

请考虑以下代码:

int main() {
    int i = 47000; // This will overflow when squared

    int i2 = square(i);

    long l = square(i);

    printf("i2 = %ld, l = %ld, i * i = %ld, square(i) = %ld",
       i2, l, i * i, square(i));

    return 0;
}

int square(int i) {
    int j = i * i;
    return j;
}

我预计输出是(由于溢出):

i2 = -2085967296, l = -2085967296, i * i = -2085967296, square(i) = -2085967296

但我得到了:

i2 = 2209000000, l = -2085967296, i * i = 2209000000, square(i) = 2209000000

你能解释一下:

a)为什么有些结果没有溢出?

b)为什么l溢出?

2 个答案:

答案 0 :(得分:3)

使用%ld打印int,您会获得未定义的行为。

您实际看到的是X86-64参数传递的工件。

当您将int返回的square值从32位显式转换为64位long时,您将签名扩展,保留溢出。这样就可以显示出预期的溢出。

传递给x86-64中的函数的前几个int零扩展到64位(后面的可能是垃圾扩展)。这应该是一种看不见的效果,因为只应使用低32位。但后来你使用%ld导致所有64位被使用。特定值溢出的方式导致零扩展到64位,意外地返回到非溢出值。

因此,将int传递给接收函数别名为long的未定义行为意外地解除了溢出。

答案 1 :(得分:0)

printf不进行类型转换。它通过省略号获取其参数(格式字符串除外),因此它必须信任格式字符串以告诉它输入值的类型是什么。

"%ld"告诉printf相应的值的类型为long inti2i * isquare(i)的值均为int类型。因此格式说明符错误,显示的值是无意义的。将"%d"用于int