C:将最小32位整数(-2147483648)强制转换为浮点,则给出正数(2147483648.0)
我在做一个嵌入式项目的时候,遇到了一件我认为很奇怪的事情。我设法在代码板上复制了它(见下文)以进行确认,但在我的机器上没有任何其他C编译器在其上进行尝试 场景:我有一个C:将最小32位整数(-2147483648)强制转换为浮点,则给出正数(2147483648.0),c,floating-point,int,long-integer,minimum,C,Floating Point,Int,Long Integer,Minimum,我在做一个嵌入式项目的时候,遇到了一件我认为很奇怪的事情。我设法在代码板上复制了它(见下文)以进行确认,但在我的机器上没有任何其他C编译器在其上进行尝试 场景:我有一个#定义一个32位整数可以容纳的最大负值,然后我尝试使用它与一个浮点值进行比较,如下所示: #define INT32_MIN (-2147483648L) void main() { float myNumber = 0.0f; if(myNumber > INT32_MIN) {
#定义一个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!!");
}
}
代码板链接:
在我看来,这段代码应该可以正常工作,但令我惊讶的是,它打印出来的宇宙被打破了代码>
此代码隐式地将INT32_MIN
强制转换为浮点值
,但结果表明,这会导致浮点值2147483648.0
(正值!),即使浮点类型完全能够表示-2147483648.0
有人对这种行为的原因有什么见解吗
代码解决方案:正如Steve Jessop在他的回答中提到的,limits.h
和stdint.h
已经包含正确(有效)的int
范围define
了,所以我现在使用它们而不是我自己的\define
问题/解决方案解释摘要:给出了答案和讨论,我认为这是一个很好的总结(注意:仍然阅读答案/评论,因为它们提供了更详细的解释):
- 我使用的是32位
long
s的C89编译器,因此任何大于long\u MAX
且小于或等于ULONG\u MAX
并后跟L
后缀的值都具有无符号long
(-2147483648L)
实际上是无符号长
(见上一点)值上的一元-
:-(2147483648L)
。此求反操作将值“包装”为2147483648
的无符号长
值(因为32位无符号长
的范围为0
-4294967295
)
- 此
无符号长
数字在打印为int
或传递给函数时,看起来像预期的负int
值,因为它第一次被强制转换为int
,这将超出范围2147483648
环绕到-2147483648
(因为32位int
s的范围为-2147483648到2147483647)
- 但是,转换为
float
时,使用实际的无符号long
值2147483648
进行转换,从而产生2147483648.0
的浮点值
更换
#define INT32_MIN (-2147483648L)
与
-2147483648
被编译器解释为对2147483648
的求反,这会导致int
溢出。因此,您应该改为编写(-2147483647-1)
。
不过,这都是标准的C89
。参见Steve Jessop对C99
的回答
另外,long
在32位机器上通常是32位的,在64位机器上是64位的。int
在这里完成任务。在具有32位long
的C89中,2147483648L
具有类型无符号长int
(参见3.1.3.2整数常量)因此,一旦将模运算应用于一元减运算,INT32_MIN
就是类型为无符号长的正值2147483648
在C99中,如果long
大于32位,则2147483648L
的类型为long
,否则为long
(参见6.4.4.1整数常量)。因此没有问题,INT32_MIN
是负值-2147483648,类型为long
或long
类似地,在long
大于32位的C89中,2147483648L
具有类型long
,INT32_MIN
为负值
我猜您使用的是一个32位长的C89编译器
一种看待它的方法是C99修复了C89中的一个“错误”。在C99中,没有U
后缀的十进制文字总是有符号类型,而在C89中,它可能是有符号的,也可能是无符号的,这取决于它的值
顺便说一句,您可能应该做的是包括limits.h
并使用INT\u MIN
作为INT
的最小值,使用LONG\u MIN
作为LONG
的最小值。它们具有正确的值和预期的类型(INT\u MIN
是一个INT
,LONG\u MIN
是一个LONG
)。如果您需要精确的32位类型,那么(假设您的实现是2的补充):
- 对于不必是可移植的代码,您可以使用您喜欢的正确大小的类型,并声明它是安全的
- 对于必须可移植的代码,请搜索可在C89编译器上运行的C99头版本
stdint.h
,并从中使用int32_t
和int32_MIN
- 如果所有其他操作都失败,请自己编写
stdint.h
,并使用WiSaGaN答案中的表达式。如果int
至少为32位,则它的类型为int
,否则为long
fwiw,如果你使用gcc 4.2.1,宇宙不会被破坏。(所以你对编译器的看法可能是对的。)你是在32位系统上吗?请注意,-是一个运算符。它不是整数文本的一部分。不能用gcc 4.2.1进行复制。你使用的是什么编译器?我可以用gcc 3.1进行复制。是的,我知道这有点旧:-)在32位系统上使用gcc 4.6时,gcc-std=c90
产生观察到的行为,gcc-std=c99
工作“如预期”。另请参见包含一些标准讨论的这个问题。更具体地说,编写-2147483648会导致编译器将其计算为-(2147
#define INT32_MIN (-2147483647 - 1)