我正在开发一个嵌入式项目,当时我遇到了一些我认为很奇怪的行为。我设法在键盘上重现它(见下文)来确认,但我的机器上没有任何其他 C 编译器来尝试它。
场景:我有一个
#define
表示 32 位整数可以容纳的最大负值,然后我尝试用它来与浮点值进行比较,如下所示:
#define INT32_MIN (-2147483648L)
void main()
{
float myNumber = 0.0f;
if(myNumber > INT32_MIN)
{
printf("Everything is OK");
}
else
{
printf("The universe is broken!!");
}
}
键盘链接:http://codepad.org/cBneMZL5
对我来说,这段代码看起来应该可以正常工作,但令我惊讶的是它打印出来了
The universe is broken!!
。
此代码隐式将
INT32_MIN
转换为 float
,但事实证明,这会导致浮点值 2147483648.0
(正数!),即使浮点类型完全能够表示 -2147483648.0
.
有人对这种行为的原因有任何见解吗?
代码解决方案:正如 Steve Jessop 在他的回答中提到的,
limits.h
和stdint.h
已经包含正确的(工作)int
范围define
,所以我现在使用这些而不是我自己的#define
问题/解决方案说明摘要:鉴于答案和讨论,我认为这是对正在发生的事情的一个很好的总结(注意:仍然阅读答案/评论,因为它们提供了更详细的解释):
long
的 C89 编译器,因此任何大于 LONG_MAX
且小于或等于 ULONG_MAX
后跟 L
后缀的值都具有 unsigned long
(-2147483648L)
实际上是 -
(参见上一点)值 unsigned long
上的一元 -(2147483648L)
。此否定操作将值“包装”为 unsigned long
的 2147483648
值(因为 32 位 unsigned long
的范围为 0
- 4294967295
)。unsigned long
数字 看起来 就像预期的负 int
值一样,当它被打印为 int
或传递给函数时,因为它首先被转换为 int
,这将其包装出来-范围 2147483648
到 -2147483648
(因为 32 位 int
的范围是 -2147483648 到 2147483647)float
时,使用实际的 unsigned long
值 2147483648
进行转换,从而得到 2147483648.0
的浮点值。更换
#define INT32_MIN (-2147483648L)
与
#define INT32_MIN (-2147483647 - 1)
-2147483648
被编译器解释为 2147483648
的否定,这会导致 int
溢出。所以你应该写 (-2147483647 - 1)
来代替。C89
标准。请参阅 Steve Jessop 的回答 C99
。long
在 32 位计算机上通常为 32 位,在 64 位计算机上通常为 64 位。 int
事情就在这里完成。
在具有 32 位
long
的 C89 中,2147483648L
具有类型 unsigned long int
(请参阅 3.1.3.2 整数常量)。因此,一旦将模算术应用于一元减运算,INT32_MIN
就是正值 2147483648,类型为 unsigned long
。
在 C99 中,如果
2147483648L
大于 32 位,则 long
具有类型 long
,否则为 long long
(请参见 6.4.4.1 整数常量)。所以没有问题,INT32_MIN
是负值-2147483648,类型为long
或long long
。
类似地,在
long
大于 32 位的 C89 中,2147483648L
具有类型 long
并且 INT32_MIN
为负数。
我猜你使用的是 32 位的 C89 编译器
long
。
一种看待它的方式是,C99 修复了 C89 中的一个“错误”。在 C99 中,没有
U
后缀 always 的十进制文字具有有符号类型,而在 C89 中,它可能是有符号的或无符号的,具体取决于其值。
顺便说一句,您可能应该做的是包含
limits.h
并使用 INT_MIN
作为 int
的最小值,并使用 LONG_MIN
作为 long
的最小值。它们具有正确的值 和 预期类型(INT_MIN
是 int
,LONG_MIN
是 long
)。如果您需要精确的 32 位类型(假设您的实现是 2 的补码):
stdint.h
,然后使用其中的 int32_t
和 INT32_MIN
。stdint.h
,并使用WiSaGaN答案中的表达式。如果 int
至少为 32 位,则其类型为 int
,否则为 long
。