我有一个简单的程序:
#include <stdio.h>
#define INT32_MIN (-0x80000000)
int main(void)
{
long long bal = 0;
if(bal < INT32_MIN )
{
printf("Failed!!!");
}
else
{
printf("Success!!!");
}
return 0;
}
条件if(bal < INT32_MIN )
始终为真。怎么可能?
如果我将宏更改为:
,它可以正常工作#define INT32_MIN (-2147483648L)
有人可以指出这个问题吗?
答案 0 :(得分:359)
这非常微妙。
程序中的每个整数文字都有一个类型。它的类型由6.4.4.1中的表格规定:
Suffix Decimal Constant Octal or Hexadecimal Constant
none int int
long int unsigned int
long long int long int
unsigned long int
long long int
unsigned long long int
如果字面数字不能适合默认的int
类型,它将尝试下一个更大的类型,如上表所示。因此对于常规十进制整数文字,它就像:
int
long
long long
。 Hex文字的行为有所不同!如果文字不适合像[{1}}这样的签名类型,它会先尝试int
然后继续尝试更大的类型。请参阅上表中的差异。
因此,在32位系统上,您的文字unsigned int
的类型为0x80000000
。
这意味着您可以在文字上应用一元unsigned int
运算符而不调用实现定义的行为,就像溢出有符号整数时一样。相反,您将获得值-
,这是一个正值。
0x80000000
调用通常的算术转换,表达式bal < INT32_MIN
的结果从0x80000000
升级到unsigned int
。值long long
保留,0小于0x80000000,因此结果为。
当您使用0x80000000
替换文字时,您使用十进制表示法,因此编译器不会选择2147483648L
,而是尝试将其放入unsigned int
。此外,L后缀表示如果可能,您需要long
。如果你继续阅读6.4.4.1中提到的表格,L后缀实际上也有类似的规则:如果数字不适合所请求的long
,它在32位的情况下不适用,编译器会给你一个long
,它可以很好地适合。
答案 1 :(得分:26)
0x80000000
是一个unsigned
字面值,其值为2147483648。
在仍然上应用一元减号会为您提供一个非零值的无符号类型。 (事实上,对于非零值x
,您最终得到的值为UINT_MAX - x + 1
。)
答案 2 :(得分:23)
此整数文字0x80000000
的类型为unsigned int
。
根据C标准(6.4.4.1整数常数)
5整数常量的类型是对应的第一个 可以表示其值的列表。
这个整数常量可以用unsigned int
的类型表示。
所以这个表达
-0x80000000
具有相同的unsigned int
类型。而且它具有相同的价值
{2}补码表示中的0x80000000
计算以下方式
-0x80000000 = ~0x80000000 + 1 => 0x7FFFFFFF + 1 => 0x80000000
如果要编写例如
,这会产生副作用int x = INT_MIN;
x = abs( x );
结果将再次为INT_MIN
。
因此在这种情况下
bal < INT32_MIN
根据通常的算术转换规则,将0
与无符号值0x80000000
进行比较,转换为long long int类型。
很明显,0小于0x80000000
。
答案 3 :(得分:12)
数字常量0x80000000
的类型为unsigned int
。如果我们采用-0x80000000
并对其进行2s恭维数学运算,我们就会得到:
~0x80000000 = 0x7FFFFFFF
0x7FFFFFFF + 1 = 0x80000000
所以-0x80000000 == 0x80000000
。比较(0 < 0x80000000)
(因为0x80000000
是无符号的)是真的。
答案 4 :(得分:11)
认为-
是数字常量的一部分时会出现混淆。
在下面的代码0x80000000
中是数字常量。它的类型仅在此确定。之后会应用-
,不会更改类型。
#define INT32_MIN (-0x80000000)
long long bal = 0;
if (bal < INT32_MIN )
原始未加修饰的数字常量是正数。
如果是十进制,则分配的类型是第一种类型:int
,long
,long long
。
如果常量是八进制或十六进制,它将获得第一个包含它的类型:int
,unsigned
,long
,unsigned long
,long long
, unsigned long long
。
0x80000000
获取unsigned
或unsigned long
的类型。无论哪种方式,它都是一些无符号类型。
-0x80000000
也是一些非零值并且是一些无符号类型,它大于0.当代码将其与long long
进行比较时,值不是在比较的两边改变了,所以0 < INT32_MIN
是真的。
另一种定义避免了这种奇怪的行为
#define INT32_MIN (-2147483647 - 1)
让我们在幻想的土地上走一段时间int
和unsigned
是48位。
然后0x80000000
适合int
,int
类型也适合-0x80000000
。 0x80000000
则为负数,打印结果不同。
[回到实词]
由于some_signed_MAX
在签名类型之前符合某些无符号类型,因为它仅在some_unsigned_MAX
内大于background: url('dropdown_arrow.png') no-repeat;
,因此它是一些无符号类型。
答案 5 :(得分:8)
C有一个规则,即整数文字可以是signed
或unsigned
取决于它是否适合signed
或unsigned
(整数提升)。在32
位机器上,文字0x80000000
将为unsigned
。在32位计算机上,-0x80000000
的2 0x80000000
补码为bal < INT32_MIN
。因此,比较signed
介于unsigned
和unsigned int
之间,根据C规则进行比较long long
将转换为bal < INT32_MIN
。
[...]否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为类型带有符号整数类型的操作数。
因此,true
始终为Group
。