0x00 INT_MIN的值为什么不能直接表示

如果你写出下面的代码,然后使用Visual Studio编译的话,就会爆出C4146错误来。告诉你这个数字不能直接写进代码里。

1
2
3
4
5
void check(int i)
{
if (i > -2147483648) // 爆出错误:C4146
// do somethings
}

这是为什么呢?

编译器在处理数字-2147483648时,不会将其看做是一个数字,而是看做一个表达式,在处理时会走两步:

  1. 首先处理数字2147483648,这个数字超出了int类型的定义域,故其被临时存储成了unsigned int类型,这在内存中是这样的:0x80000000

  2. 对这个unsigned int类型的数字2147483648作用负号,负数在计算机中使用补码表示,对0x80000000计算补码:

    1
    2
    3
    4
    5
    6
    7
       0x80000000表示为二进制为:
    ‭1000 0000 0000 0000 0000 0000 0000 0000
    其反码为:
    ‭0111 1111 1111 1111 1111 1111 1111 1111
    由补码=反码+1得:
    补码=‭1000 0000 0000 0000 0000 0000 0000 0000‬
    将其转换为16进制恰好又等于0x80000000
  3. 得到的结果恰巧还是2147483648。这就导致-2147483648在实际计算时变成了2147483648。

同理,这也导致了下面的代码将会输出true

1
std::cout << (INT_MIN == 2147483648 ? "true" : "false");

因为后面的2147483648为unsigned int类型,导致在比较时前面的INT_MIN也将由signed int升格为unsigned int类型,最终导致他俩相等。

因此,在C/C++中,对于数字-2147483648的表述是这样的:

1
#define INT_MIN     (-2147483647 - 1)

不直接写出其值,而是使用这样的一个减法操作来进行表述。且微软官方文档也建议在代码中使用INT_MIN来代替直接使用其值。

0x01 INT_MIN的绝对值怎么求

INT_MIN的绝对值怎么求,用abs函数吗?如果我们用abs函数求解INT_MIN的绝对值的话,返回结果仍是INT_MIN,这是因为abs函数返回值的缘故,abs函数输入一个int,返回一个int。而INT_MIN的绝对值等于INT_MAX+1,这样,超出int类型的定义域后的那个加1将会其值重新变为INT_MIN,这就导致了INT_MIN的绝对值还等于INT_MIN的情况。所以,此处我们需要使用llabs函数来将其强制转化为long long类型来求绝对值。