我一直在参加编程范例的讲座'斯坦福大学。在那里我遇到了以下代码:
int l = 10;
float m = *(float*)&l;
我知道第一次施法完成然后解除引用。
如何将值分配给m
?这种铸件有什么特别之处,即简单铸造就可以通过简单地进行(float)
。
此投射的特殊之处以及如何将值赋给变量?
注意:此代码可能仅供理论使用,但我想了解其背后的概念。
答案 0 :(得分:4)
以下声明:
*(float*)&l;
使用
&
地址,*
间接和(float*)
c-style cast,运算符。
所有这些运算符在operator precedence列表中排名第3,它们都是从右到左阅读的。
首先,l
的地址被采用。接下来,该地址被转换为float*
(浮点指针)。最后,使用*
取消引用此地址以读取该值。最后一步是未定义的行为。
这是违反strict aliasing rule的未定义行为。它可能会为你制作一杯茶,或者它可能会将这些碎片重新解释为漂浮物。
在我的系统上发生以下情况:
在地址l
(小端):
0x000000FC780FFC94 0a 00 00 00
地址m
:
0x0000004547B5F874 0a 00 00 00
l
,解释为int
是:10
m
,解释为float
为:1.401e-44#DEN
此结果(在我的系统上)的原因是int
和float
大小相同(msvc 64位上为4个字节),浮点数interpreted from binary 1010为1.401 e-44#DEN:
答案 1 :(得分:1)
首先,警告:根据C ++标准,这是未定义的行为。编译器在执行此行时可以自由地使程序执行任何,并且在许多情况下它不会执行程序员期望的操作。但是,对于那些熟悉C ++的人来说,意图有明确的含义,在大多数情况下,编译器可能这样做。
首先,让我们来看看如果你按预期使用(float)l
会发生什么。程序将取l
的值,解释为int
,并返回具有相同值的浮点数;在这种情况下,那是10.0
。这通常是你想要的,并且是完全明确的。
现在,让我们看看你实际拥有的代码:*(float*)&l;
。根据此表达式的特定语法,应从右向左阅读。 &l
部分表示“获取l
存储在内存中的位置”,通常称为“指向l
的指针”。由于l
是int
,因此此表达式的类型为“指向int
的指针”。
然后,(float*)
部分是演员。它说“将指针指向 - int
作为指针指向 - float
”。这应该是指向内存中相同位置的指针,但是当程序访问它时,它会将该位置的位读取为float
。
第一个*
取消引用此指针指向float
,并获取float
。这是未定义的部分;该语言假定您不会访问与两种不同类型相同的指针。它被称为“指针别名”,并且根据平台,编译器,优化标志等可以做任何事情。 预期的行为可能是为float
提供与int
相同的位模式,其值为10.
要了解这意味着什么,我们需要了解float
和int
在硬件级别的存储方式。 int
只是存储为具有相同值的二进制数,some complications为负数。 float
为more complicated,如果float
和int
与endianness存储不同,则会出现更多复杂情况。
f
的最可能值是,described by rex,1.4e-44(即负数44的十倍至1.4倍)。如果float
和int
s具有不同的字节顺序,则另一个合理的值约为6.16e-33。