C:将最小 32 位整数 (-2147483648) 转换为浮点数给出正数 (2147483648.0) [英] C: Casting minimum 32-bit integer (-2147483648) to float gives positive number (2147483648.0)

查看:33
本文介绍了C:将最小 32 位整数 (-2147483648) 转换为浮点数给出正数 (2147483648.0)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我遇到一些我认为奇怪的行为时,我正在做一个嵌入式项目.我设法在键盘上重现它(见下文)以确认,但我的机器上没有任何其他 C 编译器可以在它们上试用.

I was working on an embedded project when I ran into something which I thought was strange behaviour. I managed to reproduce it on codepad (see below) to confirm, but don't have any other C compilers on my machine to try it on them.

场景:我有一个 #define 用于 32 位整数可以容纳的最大负值,然后我尝试使用它与浮点值进行比较,如下所示:

Scenario: I have a #define for the most negative value a 32-bit integer can hold, and then I try to use this to compare with a floating point value as shown below:

#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!!.

To me it looks as though this this code should work fine, but to my surprise it prints out The universe is broken!!.

此代码将 INT32_MIN 隐式转换为 float,但事实证明这会导致 2147483648.0 的浮点值(正!),即使浮点类型完全能够表示 -2147483648.0.

This code implicitly casts the INT32_MIN to a float, but it turns out that this results in a floating point value of 2147483648.0 (positive!), even though the floating point type is perfectly capable of representing -2147483648.0.

有人对这种行为的原因有任何见解吗?

Does anyone have any insights into the cause of this behaviour?

代码解决方案:正如 Steve Jessop 在他的回答中提到的,limits.hstdint.h 包含正确(工作)int range defines 已经,所以我现在使用这些而不是我自己的 #define

CODE SOLUTION: As Steve Jessop mentioned in his answer, limits.h and stdint.h contain correct (working) int range defines already, so I'm now using these instead of my own #define

问题/解决方案解释摘要:鉴于答案和讨论,我认为这是对正在发生的事情的一个很好的总结(注意:仍然阅读答案/评论,因为它们提供了更详细的解释):

PROBLEM/SOLUTION EXPLANATION SUMMARY: Given the answers and discussions, I think this is a good summary of what's going on (note: still read the answers/comments because they provide a more detailed explanation):

  • 我正在使用具有 32 位 long 的 C89 编译器,因此任何大于 LONG_MAX 且小于或等于 ULONG_MAX 的值后跟 L 后缀的类型为 unsigned long
  • (-2147483648L) 实际上是 unsigned long 上的一元 -(参见上一点)值:-(2147483648L).此否定操作将值包装"为 2147483648unsigned long 值(因为 32 位 unsigned long 具有范围 <代码>0 - 4294967295).
  • 这个 unsigned long 数字 看起来 当它被打印为 int 或传递给一个函数,因为它首先被强制转换为一个 int,它将这个超出范围的 2147483648 包装到 -2147483648 (因为 32 位 int 的范围是 -2147483648 到 2147483647)
  • 然而,转换为 float 是使用实际的 unsigned long2147483648 进行转换,导致浮点值2147483648.0.
  • I'm using a C89 compiler with 32-bit longs, so any values greater than LONG_MAX and less or equal to ULONG_MAX followed by the L postfix have a type of unsigned long
  • (-2147483648L) is actually a unary - on an unsigned long (see previous point) value: -(2147483648L). This negation operation 'wraps' the value around to be the unsigned long value of 2147483648 (because 32-bit unsigned longs have the range 0 - 4294967295).
  • This unsigned long number looks like the expected negative int value when it gets printed as an int or passed to a function because it is first getting cast to an int, which is wrapping this out-of-range 2147483648 around to -2147483648 (because 32-bit ints have the range -2147483648 to 2147483647)
  • The cast to float, however, is using the actual unsigned long value 2147483648 for conversion, resulting in the floating-point value of 2147483648.0.

推荐答案

在 32 位 long 的 C89 中,2147483648L 的类型为 unsigned long int(参见 3.1.3.2 整数常量).因此,一旦将模运算应用于一元减法运算,INT32_MIN 就是 unsigned long 类型的正值 2147483648.

In C89 with a 32 bit long, 2147483648L has type unsigned long int (see 3.1.3.2 Integer constants). So once modulo arithmetic has been applied to the unary minus operation, INT32_MIN is the positive value 2147483648 with type unsigned long.

在 C99 中,如果 long 大于 32 位,则 2147483648L 的类型为 long,否则为 long long(见 6.4.4.1 整数常量).所以没有问题,INT32_MIN 是负值 -2147483648,类型为 longlong long.

In C99, 2147483648L has type long if long is bigger than 32 bits, or long long otherwise (see 6.4.4.1 Integer constants). So there is no problem and INT32_MIN is the negative value -2147483648 with type long or long long.

类似地,在 C89 中,long 大于 32 位,2147483648L 的类型为 long,而 INT32_MIN 为负数.

Similarly in C89 with long larger than 32 bits, 2147483648L has type long and INT32_MIN is negative.

我猜你正在使用带有 32 位 long 的 C89 编译器.

I guess you're using a C89 compiler with a 32 bit long.

一种看待它的方式是 C99 修复了 C89 中的一个错误".在 C99 中,没有 U 后缀 always 的十进制文字具有有符号类型,而在 C89 中,它可能是有符号或无符号的,具体取决于其值.

One way to look at it is that C99 fixes a "mistake" in C89. In C99 a decimal literal with no U suffix always has signed type, whereas in C89 it may be signed or unsigned depending on its value.

顺便说一句,您可能应该做的是包含 limits.h 并使用 INT_MIN 作为 int 的最小值,并且 LONG_MIN 表示 long 的最小值.它们具有正确的值预期的类型(INT_MINintLONG_MINlong).如果您需要一个精确的 32 位类型,那么(假设您的实现是 2 的补码):

What you should probably do, btw, is include limits.h and use INT_MIN for the minimum value of an int, and LONG_MIN for the minimum value of a long. They have the correct value and the expected type (INT_MIN is an int, LONG_MIN is a long). If you need an exact 32 bit type then (assuming your implementation is 2's complement):

  • 对于不需要可移植的代码,您可以使用任何您喜欢的大小正确的类型,并断言它是安全的.
  • 对于必须可移植的代码,搜索适用于 C89 编译器的 C99 头文件 stdint.h 版本,并使用 int32_tINT32_MIN .
  • 如果所有其他方法都失败,请自己编写 stdint.h,并使用 WiSaGaN 答案中的表达式.如果 int 至少为 32 位,则它的类型为 int,否则为 long.
  • for code that doesn't have to be portable, you could use whichever type you prefer that's the correct size, and assert it to be on the safe side.
  • for code that has to be portable, search for a version of the C99 header stdint.h that works on your C89 compiler, and use int32_t and INT32_MIN from that.
  • if all else fails, write stdint.h yourself, and use the expression in WiSaGaN's answer. It has type int if int is at least 32 bits, otherwise long.

这篇关于C:将最小 32 位整数 (-2147483648) 转换为浮点数给出正数 (2147483648.0)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆