C:将最小 32 位整数 (-2147483648) 转换为浮点数给出正数 (2147483648.0) [英] C: Casting minimum 32-bit integer (-2147483648) to float gives positive number (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.h
和 stdint.h
包含正确(工作)int
range define
s 已经,所以我现在使用这些而不是我自己的 #define
CODE SOLUTION: As Steve Jessop mentioned in his answer, limits.h
and stdint.h
contain correct (working) int
range define
s 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)代码>.此否定操作将值包装"为
-2147483648
的unsigned long
值(因为 32 位unsigned long
具有范围 <代码>04294967295
).- 这个
unsigned long
数字 看起来 当它被打印为int
或传递给一个函数,因为它首先被强制转换为一个int
,它将这个超出范围的2147483648
包装到-2147483648
(因为 32 位int
的范围是 -2147483648 到 2147483647) - 然而,转换为
float
是使用实际的unsigned long
值2147483648
进行转换,导致浮点值2147483648.0
.
- I'm using a C89 compiler with 32-bit
long
s, so any values greater thanLONG_MAX
and less or equal toULONG_MAX
followed by theL
postfix have a type ofunsigned long
(-2147483648L)
is actually a unary-
on anunsigned long
(see previous point) value:-(2147483648L)
. This negation operation 'wraps' the value around to be theunsigned long
value of2147483648
(because 32-bitunsigned long
s have the range0
-4294967295
).- This
unsigned long
number looks like the expected negativeint
value when it gets printed as anint
or passed to a function because it is first getting cast to anint
, which is wrapping this out-of-range2147483648
around to-2147483648
(because 32-bitint
s have the range -2147483648 to 2147483647) - The cast to
float
, however, is using the actualunsigned long
value2147483648
for conversion, resulting in the floating-point value of2147483648.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,类型为 long
或 long 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_MIN
是 int
,LONG_MIN
是 long代码>).如果您需要一个精确的 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_t
和INT32_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 useint32_t
andINT32_MIN
from that. - if all else fails, write
stdint.h
yourself, and use the expression in WiSaGaN's answer. It has typeint
ifint
is at least 32 bits, otherwiselong
.
这篇关于C:将最小 32 位整数 (-2147483648) 转换为浮点数给出正数 (2147483648.0)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!