我正在阅读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
溢出?
答案 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 int
。 i2
,i * i
和square(i)
的值均为int
类型。因此格式说明符错误,显示的值是无意义的。将"%d"
用于int
。