C 为什么最小的int−;2147483648,具有类型';长';?

C 为什么最小的int−;2147483648,具有类型';长';?,c,types,C,Types,对于一个学校项目,我必须编写C函数printf。事情进展得很顺利,但有一个问题我找不到好的答案,所以我来了 printf("PRINTF(d) \t: %d\n", -2147483648); 告诉我(gcc-Werror-Wextra-Wall): 但如果我使用int变量,一切都很顺利: int i; i = -2147483648; printf("%d", i); 为什么? 编辑: 我理解很多观点,它们非常有趣。无论如何,我猜printf正在使用库,因此,va_arg(va_list

对于一个学校项目,我必须编写C函数printf。事情进展得很顺利,但有一个问题我找不到好的答案,所以我来了

printf("PRINTF(d) \t: %d\n", -2147483648);
告诉我(
gcc-Werror-Wextra-Wall
):

但如果我使用int变量,一切都很顺利:

int i;

i = -2147483648;
printf("%d", i);
为什么?

编辑:
我理解很多观点,它们非常有趣。无论如何,我猜
printf
正在使用
库,因此,
va_arg(va_list ap,type)
也应该返回正确的类型。对于
%d
%i
,返回的类型显然是
int
。它改变了什么吗?

在C中,
-2147483648
不是一个整数常量
2147483648
是一个整数常量,
-
只是应用于它的一元运算符,生成一个常量表达式。
2147483648
的值不适合
int
(它太大了,
2147483647
通常是最大的整数),因此整数常量的类型为
long
,这会导致您观察到的问题。如果要提及
int
的下限,请使用
中的宏
int\u MIN
(便携式方法),或小心避免提及
2147483648

printf("PRINTF(d) \t: %d\n", -1 - 2147483647);

问题在于
-2147483648
不是整数文本。它是一个由一元求反运算符
-
和整数
2147483648
组成的表达式,如果
int
s为32位,则该整数太大,不可能是
int
。由于编译器将在应用求反运算符之前选择一个大小合适的有符号整数来表示
2147483648
,因此结果的类型将大于
int

如果您知道
int
s是32位的,并且希望避免警告而不破坏可读性,请使用显式强制转换:

printf("PRINTF(d) \t: %d\n", (int)(-2147483648));
这是32位
int
s的2的补码机器上定义的行为

为了提高理论上的可移植性,请使用
INT_MIN
而不是数字,并告诉我们您在哪里找到了非2的s-complete机器来测试它


要明确的是,最后一段在一定程度上是一个笑话<如果你的意思是“最小的
INT
”,那么code>INT\u MIN无疑是一个不错的选择,因为
INT
的大小各不相同。例如,仍然有很多16位实现。写出-231只有在您总是明确表示该值时才有用,在这种情况下,您可能会使用固定大小的类型,如
int32\t
,而不是
int

对于那些可能没有注意到
2147483648
21744833648
之间差异的人来说,您可能需要一些替代方法,而不是以十进制形式写出数字,以使其更清晰,但您需要小心

如上所述,在32位2的补码机器上,
(int)-2147483648
不会溢出,因此定义良好,因为
-2147483648
将被视为更宽的有符号类型。但是,对于
(int)(-0x8000000)
,情况并非如此<代码>0x8000000将被视为
无符号int
(因为它适合无符号表示)<代码>-0x8000000定义良好(但是如果
int
为32位,
-
则无效),并且生成的
无符号int
0x8000000
int
的转换涉及溢出。为了避免溢出,您需要将十六进制常量转换为有符号类型:
(int)((long-long)(0x8000000))


同样,如果要使用左移位运算符,则需要小心
1定义
INT_MIN
的常规方法是
\define INT_MIN(-(INT_MAX)-1
,(这就避免了你所描述的取长的负数的问题。@abelenky:我知道在2s补码机上通常是这样定义的
INT\u MIN
。否则,我想把它定义为
(-INT\u MAX)
,因为只键入2147483647一次是有意义的。但是它是(合理地)建议使用
-2147483647-1
调用printf有点奇怪。当然,既然我们已经讨论过了,我们知道为什么必须这样做。我只是建议使用显式cast可以让您以通常由既不是编译器也不是语言律师的人编写的形式编写文本数:)我已经回答了你的其他问题,但是我的评论被删除了:
va_arg()
不知道您尝试获取的参数的类型。您需要知道,如果您尝试获取的类型与作为参数传递的类型不同,这是未定义的行为。如果您执行
printf(“%d\n”,-2147483648),这也适用
由于参数的类型为
long
,但
printf
尝试获取
int
。而不是重复。如果您阅读了另一个问题的接受答案,则是由于特定于问题上下文的未定义行为。此问题与未定义行为无关。此问题与C有关,另一个与C有关++。两种语言的促销规则相似,但可能存在细微差异。这个问题将有助于更多的未来访客,如果投票数高得多的话,可能已经有了。这也不是第二个问题的重复。关键事实是,他们用十六进制指定了文字,这意味着它是无符号整数而不是有符号的长。@AdrianMcCarthy他们用十六进制指定了文字,这意味着它是无符号的整型而不是有符号的长型。这可以理解为“十六进制常量总是无符号的”。旧的前标准C编译器经常使十六进制常量无符号,这可能会引起混淆。Per:“整型常量的类型是
printf("PRINTF(d) \t: %d\n", (int)(-2147483648));
(int)(-(1LL<<31))