`#define INT_MIN 0x80000000` 好吗?

计算科学 计算机算术 数值限制
2021-12-07 15:52:32

在计算机系统中:程序员的观点:

用 C 写 TMin 在图 2.19 和习题 2.21 中,我们仔细地将 TMin32 的值写为 -2,147,483,647-1。为什么不简单地将其写为 -2,147,483,648 或 0x80000000?查看 C 头文件 limits.h,我们看到它们使用了与我们必须编写 TMin32 和 TMax32 类似的方法:

/* Minimum and maximum values a ‘signed int’ can hold. */
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)

不幸的是,二进制补码表示的不对称性和 C 语言的转换规则之间的奇怪相互作用迫使我们以这种不寻常的方式编写 TMin32。尽管理解这个问题需要我们深入研究 C 语言标准中比较模糊的角落之一,但这将有助于我们了解整数数据类型和表示的一些微妙之处。

0x80000000是十六进制表示法,并且在有符号整数的范围内,不是吗?(怎么判断一个整数整数是有符号还是无符号呢?不就是默认不带任何后缀的整数字面量就是有符号整数吗?所以0X80000000是有符号的?在有符号的范围内,因为它是最小的有符号范围内的整数)

应该 #define INT_MIN 0x80000000没问题,而书上另有说法?

2个回答

这更像是一个适合 CS 论坛的问题,但它的不足之处在于:它要求您知道编译器如何解析数字。特别是,当编译器看到类似 的内容时-2147483648,它会将其解析为unary minus应用于2147483648. 但后者(一个正数)对于数据类型来说太大了int,因此可能会被环绕或以其他方式修改。情况也是如此:它被解析为整数,但对于数据类型0x80000000来说太大了。int

另一方面,#define INT_MIN (-INT_MAX - 1)有效:该表达式中的每个常量都适合int数据类型。

不,这不好。

C 中没有负数本身。“-12345”被解释为正数 12345 与一元减号运算符的组合。

0x80000000 超出 int 范围,将被解释为 unsigned int 类型的文字。

在大多数编译器上,您可以通过使用类型转换来解决这个问题

#define INT_MIN ((int)(0x80000000))

然而,这个表达式的行为是实现定义的。大多数编译器只会重新解释这些位,但可能有些编译器不会。

那么0X80000000是签名的吗?它在有符号范围内,因为它是有符号范围内的最小整数

不,

如果我们在具有 32 位整数的二进制补码系统上取最小的有符号整数,并将这些位重新解释为无符号整数,我们将得到值 0X80000000。

但是 0x80000000 本身仍然是一个正数,它与 INT_MIN 不同(尽管由于 Cs 类型转换规则,它有时可能会与之相等)。

如何判断整数积分是有符号还是无符号?

C 通过遍历类型列表并选择可以正确表示文字的第一个类型来选择整数文字的类型。

所述类型列表中的确切内容取决于 C 标准的版本和文字的基数。在用于十进制文字的现代 C 版本中,编译器强烈倾向于有符号类型,仅当标准有符号类型(int、long 或 long long*)都不能适合该文字时才使用无符号类型。对于十六进制文字,对带符号类型的偏好较弱,带符号的 int 仍然优于 unsigned int,但 unsigned int 优于 long 和 long long。

因此,当编译器在具有 32 位 int 的系统上查看 0x80000000 时,它会得出结论,它不适合 int,但适合 unsigned int。

* 注意:在 C89 中 long long 不是必需的类型,因此 C89 编译器可能使用 unsigned long 而不是signed long long 作为文字。