Binary representation with union

左心房为你撑大大i 提交于 2019-12-12 05:05:13

问题


In the below program:

union
{
  int i;
  float f;
} u;

Assuming 32 bit compiler, u is allocated with 4 bytes in memory.

u.f = 3.14159f;

3.14159f is represented using IEEE 754, in those 4 bytes.

printf("As integer: %08x\n", u.i);

What does u.i represent here? Is IEEE 754 binary representation interpreted as 4 byte signed int?


回答1:


Reading from i is implementation-defined blah blah blah.

Still.

On "normal" platforms where

  • float is IEEE-754 binary32 format
  • int is 32 bit 2's complement
  • the endianness of float and int is the same
  • type punning through unions is well defined (C99+)

(AKA any "regular" PC with a recent enough compiler)

you will get the integer whose bit pattern matches the one of your original float, which is described e.g. here

Now, there's the sign bit that messes up stuff with the 2's complement representation of int, so you probably want to use an unsigned type to do this kind of experimentation. Also, memcpy is a safer way to perform type-punning (you won't get dirty looks and discussions about the standard), so if you do something like:

float x = 1234.5678;
uint32_t x_u;
memcpy(&x_u, &x, sizeof x_u);

Now you can easily extract the various parts of the FP representation:

int sign     = x_u>>31;                    // 0 = positive; 1 = negative
int exponent = ((x_u>>23) & 0xff;          // apply -127 bias to obtain actual exponent
int mantissa = x_u & ~((unsigned(-1)<<23);

(notice that this ignores completely all the "magic" patterns - quiet and signaling NaNs and subnormal numbers come to mind)




回答2:


According to this answer, reading from any element of the union other than the last one written is either undefined behavior or implementation defined behavior depending on the version of the standard.

If you want to examine the binary representation of 3.14159f, you can do so by casting the address of a float and then dereferencing.

#include <stdint.h>
#include <stdio.h>


int main(){
    float f = 3.14159f;
    printf("%x\n", *(uint32_t*) &f);
}

The output of this program is 40490fd0, which matches with the result given by this page.

As interjay correctly pointed out, the technique I present above violates the strict aliasing rule. To make the above code work correctly, one must pass the flag -fno-strict-aliasing to gcc or the equivalent flag to disable optimizations based on strict aliasing on other compilers.


Another way of viewing the bytes which does not violate strict aliasing and does not require the flag is using a char * instead.

unsigned char* cp = (unsigned char*) &f;
printf("%02x%02x%02x%02x\n",cp[0],cp[1],cp[2],cp[3]);

Note that on little endian architectures such as x86, this will produce bytes in the opposite order as the first suggestion.



来源:https://stackoverflow.com/questions/40057224/binary-representation-with-union

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!