0

I have this code:

typedef union MyUnion {
    int ival;
    float fval;
} MyUnion;

MyUnion myUnion;
myUnion.fval = 3.0f;

someFuncCall(myUnion.ival);

What exactly am I doing when I ask for the ival? It is my guess that I am asking for the float to be thought of (encoded as?) an int. I also assume that it has to do with sharing the same space in memory? However, I am definitely uncertain. This is a trick I had to use when sending float data to an FPGA in the Vivado Suite. All data is expected to enter as ints. I'd really appreciate any thorough clarification for what is going on or just pointers to resources. Thanks!

eatonphil
  • 13,115
  • 27
  • 76
  • 133
  • The behaviour you're seeing is (technically) undefined. In practice, you're likely to see the raw bits of the `float` reinterpreted as if they were the raw bits of an `int`. – Oliver Charlesworth Sep 07 '14 at 12:52
  • @Oli, I know its not a great response, but this was a technique used in the Vivado documentation too. I'd be able to point it out... but their documentation is a mess. – eatonphil Sep 07 '14 at 12:54
  • @OliCharlesworth: Supposedly it's actually not undefined anymore, by virtue of one or more defect reports. See http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm or http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm if you want to try to make sense of the matter. – R.. GitHub STOP HELPING ICE Sep 07 '14 at 13:07
  • @R.. Yeah, this is an issue that never goes away ;) My thoughts on the matter that this is a seriously grey area, so it's best to steer clear and stick with "safe" approaches (i.e. `memcpy`). – Oliver Charlesworth Sep 07 '14 at 13:09
  • @OliCharlesworth: I'd actually like to see a really good SO question on interpreting the current state of the standard and DR's relevant to type punning to come up with a clear answer for what's valid. :-) But I'd have to do a good bit of preliminary research to ask a good one, I think. – R.. GitHub STOP HELPING ICE Sep 07 '14 at 13:10
  • @R..: I would certainly welcome a canonical SO reference on this! (Of course, it's not just a matter of what the standard does/doesn't say, but also whether compilers adhere to that in practice...) – Oliver Charlesworth Sep 07 '14 at 13:11
  • @R this question seems like a good enough one for that task – M.M Sep 07 '14 at 13:11
  • @OliCharlesworth: Compilers allow it all when it comes to unions. The question of what the standard allows is just important from the standpoint that compilers are going to get better at aliasing analysis and use all the assumptions they can get from the standard. – R.. GitHub STOP HELPING ICE Sep 07 '14 at 13:49
  • @phileaton: Take a look to this answer: [Unions and Type Punning](http://stackoverflow.com/questions/25664848/unions-and-type-punning/25668287#25668287) – pablo1977 Sep 07 '14 at 15:21

2 Answers2

2

According to the standard IEC9899/2011 §6.5.2.3, note 95 you have that:

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

So indeed what you are trying to do works but it could lead to problems (eg. different sizes for the members or different memory alignment).

Jack
  • 131,802
  • 30
  • 241
  • 343
  • 1
    The C standard is ISO/IEC 9899, and you should also mention what year. Such punning violates the strict aliasing rule, so I think the outcome is worse than what this suggests, with newer compilers that implement newer editions of the standard. – Potatoswatter Sep 07 '14 at 13:06
  • @Potatoswatter the wording of this clause suggests that it's supposed to supersede strict aliasing (and IIRC the standard does not clarify this anywhere else). Although this text is from a footnote, and footnotes are non-normative. – M.M Sep 07 '14 at 13:08
  • It seems to be the opinion of the committee, though it's hard to get a clear statement of this in writing, that type punning via unions is not undefined, and that it and `memcpy` are the only ways to perform type punning without UB. See the DR links I posted in comments on the question for a place to start. – R.. GitHub STOP HELPING ICE Sep 07 '14 at 13:09
  • 1
    BTW this footnote is not in C99, but it is in n1570 (C11 draft) – M.M Sep 07 '14 at 13:11
  • 2
    @Jack I think alignment cannot be a problem , a `union` is guaranteed to be aligned correctly for all of its members. "Each non-bit-field member of a structure or union object is aligned in an implementation-defined manner appropriate to its type." – M.M Sep 07 '14 at 13:13
1

You're taking raw bits of a float and interpet them as an int. A union works by allocating memory for the biggest (in terms of sizeof) field and overwriting that part of memory every time you assign a value to a union's field.

In your example sizeof(int) == sizeof(float) probably holds (both are 32 bits) and instead of using an union, you could write:

float f = 3.0f;
someFuncCall(*(int*)&f);

Generally, however, you do not know how the union's fields are aligned in memory. Take the following union:

union SomeUnion {
    char c;
    int i;
}

SomeUnion::c and SomeUnion::i might be aligned on either HO or LO boundary and it is implementation dependant.

Adam Kosiorek
  • 1,438
  • 1
  • 13
  • 17