我下面有一个简单的程序:
#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)
有人能指出这个问题吗?
这个整数字面值0x80000000的类型是unsigned int。
根据C标准(6.4.4.1整数常量)
整数常量的类型是对应的第一个
可以表示其值的列表。
这个整数常量可以用unsigned int类型表示。
这个表达式
-0x80000000具有相同的unsigned int类型。此外,它具有相同的价值
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。
在认为-是数字常数的一部分时,出现了一个混淆点。
在下面的代码中,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,在OP的系统上获取unsigned或unsigned long类型。无论哪种方式,它都是某种无符号类型。
-0x80000000也是一些非零值,并且是一些无符号类型,它大于0。当代码将其与long long进行比较时,比较两边的值不会改变,因此0 < INT32_MIN为真。
另一种定义可以避免这种奇怪的行为
#define INT32_MIN (-2147483647 - 1)
让我们在幻想的土地上漫步一会儿,在那里int和unsigned是48位的。
那么0x80000000适合int类型,int类型也是。-0x80000000是一个负数,输出的结果是不同的。
[回到现实]
由于0x80000000适合于有符号类型之前的某个无符号类型,因为它只是在some_unsigned_MAX中大于some_unsigned_MAX,因此它是某个无符号类型。