这个问题在这里已有答案:
对于学校项目,我要编写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
正在使用 <stdarg.h>
librairy,因此, va_arg(va_list ap, type)
也应该返回正确的类型 . 对于 %d
和 %i
,显然返回的类型是 int
. 它有什么改变吗?
2 回答
在C中,
-2147483648
不是整数常量 .2147483648
是一个整型常量,-
只是一个应用于它的一元运算符,产生一个常量表达式 .2147483648
的值不适合int
(它太大,2147483647
通常是最大的整数),因此整数常量的类型为long
,这会导致您观察到的问题 . 如果您想提及int
的下限,请使用<limits.h>
中的宏<limits.h>
(便携式方法)或小心避免提及2147483648
:问题是
-2147483648
不是整数文字 . 它是一个由一元否定运算符-
和整数2147483648
组成的表达式,如果int
是32位,则它太大而不能成为int
. 由于编译器将在应用否定运算符之前选择适当大小的有符号整数来表示2147483648
,因此结果的类型将大于int
.如果您知道
int
是32位,并且想要在不破坏可读性的情况下避免警告,请使用显式强制转换:那个's defined behaviour on a 2'补充机器有32位
int
s .为了提高理论上的可移植性,请使用
INT_MIN
而不是数字,并告诉我们您在哪里找到非二进制补码机器进行测试 .需要说明的是,最后一段部分是一个笑话 . 如果你的意思是“最小的
int
”,INT_MIN
肯定是要走的路,因为int
的大小不一 . 例如,仍有许多16位实现 . 写出-231只有在你绝对总是指那个值时才有用,在这种情况下你可能会使用像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位计算机上是未定义的行为;如果int
至少为33位,它将仅计算为231,因为如果k
严格小于左侧参数的整数类型的非符号位数,则左移k
位只能很好地定义 .1LL<<31
是安全的,因为long long int
需要能够代表263-1,所以它的位大小必须大于32.所以表格可能是最具可读性的 . 因人而异 .
对于任何通过的学习者,这个问题被标记为C,并且最新的C草案(n1570.pdf)表示,对于
E1 << E2
,其中E1
具有有符号类型,仅当E1
为非负且E1 × 2E2
"is representable in the result type"时才定义该值 . (§6.5.7第4段) .这与C不同,其中如果
E1
是非负的并且E1 × 2E2
“可以在结果类型的相应无符号类型中表示”,则定义左移运算符的应用(§5.8第2段,强调添加) .在C中,根据最新的标准草案,如果值不能在目标类型中表示,则整数值到有符号整数类型的转换是实现定义的(第4.7节第3段) . C标准的相应段落 - §6.3.1.3段 . 3 - 说"either the result is implementation-defined or an implementation-defined signal is raised" . )