C:将最小32位整数(-2147483648)强制转换为浮点,则给出正数(2147483648.0)

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) {

我在做一个嵌入式项目的时候,遇到了一件我认为很奇怪的事情。我设法在代码板上复制了它(见下文)以进行确认,但在我的机器上没有任何其他C编译器在其上进行尝试

场景:我有一个
#定义一个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.hstdint.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)