对于学校项目,我要编写C函数printf.事情进展顺利,但有一个问题我找不到合适的答案,所以我在这里.
printf("PRINTF(d) \t: %d\n", -2147483648);
告诉我(gcc -Werror -Wextra -Wall
):
error: format specifies type 'int' but the argument has type 'long' [-Werror,-Wformat] printf("PRINTF(d) \t: %d\n", -2147483648); ~~ ^~~~~~~~~~~ %ld
但是如果我使用int变量,一切都很顺利:
int i; i = -2147483648; printf("%d", i);
为什么?
我理解了许多观点,他们非常有趣.无论如何,我猜printf
是使用
librairy,所以,va_arg(va_list ap, type)
也应该返回正确的类型.对于%d
和%i
,显然返回的类型是int
.它有什么改变吗?
在C中,-2147483648
不是整数常量.2147483648
是一个整数常量,-
只是一个应用于它的一元运算符,产生一个常量表达式.值2147483648
不适合int
(它太大,2147483647
通常是最大的整数),因此整数常量具有类型long
,这会导致您观察到的问题.如果你想提一个下限int
,无论是使用宏INT_MIN
从
(便携式办法)或小心避免提及2147483648
:
printf("PRINTF(d) \t: %d\n", -1 - 2147483647);
问题是它-2147483648
不是整数文字.它是由一元否定操作者的表达-
和整数2147483648
,这是太大,是一个int
如果int
s为32位.由于编译器2147483648
在应用否定运算符之前将选择适当大小的有符号整数来表示,因此结果的类型将大于a int
.
如果您知道您的int
s是32位,并且想要在不破坏可读性的情况下避免警告,请使用显式强制转换:
printf("PRINTF(d) \t: %d\n", (int)(-2147483648));
这是在具有32位int
s 的2的补码机器上定义的行为.
为了提高理论上的可移植性,请使用INT_MIN
而不是使用数字,并告诉我们您在哪里找到非二进制补码机器进行测试.
要明确的是,最后一段部分是一个笑话.INT_MIN
如果你的意思是"最小的int
",那绝对是你要走的路,因为int
它的大小各不相同.例如,仍有许多16位实现.写出-2 31只有在你总是精确地指那个值时才有用,在这种情况下你可能会使用固定大小的类型int32_t
而不是int
.
你可能会想一些替代十进制写出的数量,使之更清晰对于那些谁可能没有注意到的区别2147483648
和2174483648
,但你必须要小心.
如上所述,在32位二进制补码机器上,(int)(-2147483648)
不会溢出,因此定义明确,因为-2147483648
它将作为更宽的有符号类型进行处理.但是,情况并非如此(int)(-0x80000000)
.0x80000000
将被视为一个unsigned int
(因为它适合无符号表示); -0x80000000
被良好定义(但-
如果没有效果int
是32位),并且将所得的转化unsigned int
0x80000000
到int
涉及溢出.为避免溢出,您需要将十六进制常量转换为带符号的类型:(int)(-(long long)(0x80000000))
.
同样,如果要使用左移位运算符,则需要注意.1<<31
在具有32位(或更小)int
s的32位计算机上是未定义的行为; 如果至少是33位,则它将仅评估为2 31int
,因为k
如果k
严格地小于左侧参数的整数类型的非符号位的数量,则仅按比特左移定义.
1LL<<31
是安全的,因为long long int
要求能够代表2 63 -1,所以它的位大小必须大于32.所以形式
(int)(-(1LL<<31))
可能是最具可读性的.因人而异.
对于任何通过悬挂物,这个问题被标记C,以及最新的C草案(n1570.pdf)说,相对于E1 << E2
,其中E1
有一个符号类型,该值仅被定义,如果E1
是负,并且"是结果型的可表示".(§6.5.7第4段).E1 × 2E2
这与C++不同,在C++中定义了左移运算符的应用,如果E1
它是非负的并且"可以在结果类型的相应无符号类型中表示
"(§5.8第2段,强调添加).E1 × 2E2
在C++中,根据最新的草案标准,如果值无法在目标类型中表示,则将整数值转换为有符号整数类型是实现定义的(第4.7节第3段).C标准的相应段落 - §6.3.1.3段.3 - 表示"结果是实现定义的或者实现定义的信号被引发".)