c语言里面TMin不能写成-2147483648的原因

来源:互联网 发布:java 文件编码 编辑:程序博客网 时间:2024/06/02 16:26

C语言中,将TMin(32位有符号整数的最小值)写成 -2147483647-1,而不是简单地写成 -2147483648 或 0x80000000 。这是为什么呢?

首先,对于整数常量的定义:

    An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.

可见如果不发生溢出,整型常量的值总是非负数。如果前面出现符号,则是对整型常量使用的一元运算符,而不是整型常量的一部分。整型常量的实际类型取决于长度、基数、后缀字母和C语言实现确定的类型表示精度。具体的根据表一来确定。
  
其次,看看C语言中limits.h中对于INT_MIN和INT_MAX的定义如下所示:

    #define INT_MAX 2147483647    #define INT_MIN (-INT_MAX - 1)

那么考虑到以上两点,如果将TMin32写成-2147483648并且将代码在一个32位的机器上面编译,当编译器遇到-X形式的数值,它首先会确定X的数据类型和值,然后取X的。

 ISO C90 ISO C99 十进制(Decimal) 十六进制(Hexadecimal) 十进制(Decimal) 十六进制(Hexadecimal)
int
long
unsigned
unsigned long
int
unsigned
long
unsigned long
int
long
long long
 
int
unsigned
long
unsigned long
long long
unsigned long long

表一 根据C语言版本和常量的格式(十进制和十六进制),常量的数据类型是从上面表格里选择第一个合适(能表示常量)的类型。

 Word Size ISO C90 ISO C99 Expression -2147483648 0x80000000 -2147483648 0x80000000
32
64
unsigned
long
unsigned
unsigned
long long
long
unsigned
unsigned

表二 根据C语言版本和常量的格式(十进制和十六进制),可以为这两个表达式得到三种不同的数据类型,包括数据为正值的情况。

由于2147483648超过了int所能够表示的范围,编译器就会再次选择一种可以正确的表示此值的类型。然后它就会按照第一个表格(十进制)的顺序往下继续尝试类型,再假设编译器采用的标准是ISO C90,int->long->unsigned,然后就发现unsigned是第一个合适的数据类型。正如我们知道的,2147483648和-2147483648在32位数值上拥有同样的位表示,使得此常量的最终数据类型是unsigned且值为2147483648。这对于16进制的0x80000000也是相同的结果。

对于64位来说十进制和十六进制会分别选择long(-2147483648)和unsigned(2147483648)。而ISO C99的情况则是按照上述规则数据类型为long long才能容纳2147483648。

最后结论是:-214748364832位机器里使用ISO C90进行编译,会先将2147483648看成是一个unsigned,再对2147483648进行无符号的加法逆元计算(见csapp第二版56页),得到结果是:
(-uw2147483648) = 2w - x = 232 - 231 = 231 = 2147483648。

所以对于下面的表达式:

    int result = -2147483648 < 2147483647;

在32位机器里面使用ISO C90进行编译, result = 0。

参考资料:
cs: app web aside

0 0
原创粉丝点击