#include <stdio.h> #include <stdlib.h> union IFC { int i; float f; char c; }; int main(void) { union IFC ifc = {.f = 3.14}; printf("Union's float is %.2f\n", ifc.f); // 3.14 ifc.i = 2; printf("Union's integer is %d\n", ifc.i); // 2 ifc.c = 'A'; printf("Union's character is %c\n", ifc.c); // A printf("Union's float is %.2f\n", ifc.f); // 0.00 return 0; } 

How does this code work at the memory level of the computer? Where inf.f value 0.00 from inf.f from when the union uses inf.c ? I understand that one union occupies the same number of bytes in any state allowed for it (in my case, int / float / char ). But after all, these bytes store only one value. Why, if at the given moment of time the 'A' symbol is stored there, can I still contact the union for the real number inf.f ? Although it is not what I once asked, although it always equals zero, it still returns. How it works?

  • "Even though it always equals zero" - did not check, but probably not zero, but a very, very small number that you round off and because of that you see zero - andreymal
  • Often union s are used as a 'fast' converter of one to another, because the memory for all 'convertible' elements is the same. - NewView
  • @NewView - you cannot do such a conversion, because the sequence "writing field A" - "reading field B" leads to undefined behavior. - gbg
  • @gbg, I probably don’t know something, but the union is the one for this purpose - “recording field A” - “reading field B” - otherwise what’s the point of using it? As an example, typical implementations of the md5, sha1-512 hashes, and so on use the union's new one - NewView
  • one
    @NewView: The point of using a union is first and foremost in saving memory by reusing it to store different data at different times. It is for this purpose that the union has always been intended. Simultaneous work with several fields is not necessary for this. Using union to re-interpret memory is a secondary minor functionality of the union, also prohibited in C ++. - AnT 2:12 pm

4 answers 4

First, the C language ensures that all the union fields have the same address that matches the entire union. In practice, this means that all union fields are stored with overlapping at the same address in memory. The union size will be equal to the size of its maximum field (plus, possibly, some additional unused bytes added for alignment purposes).

Secondly, the C language says that assigning a value to some kind of union field causes unused bytes in this field to an undefined state . For this reason, since the char c field on your platform is likely to be smaller than the float f field, it makes no sense to read the f field after assigning a value to the c field - this will generally lead to undefined behavior. In practice, it is quite reasonable to assume that even within one program, one entry of the value of c can affect all the bytes of your union, and the other - only the bytes of c .

Union in C can be used to re-interpret an object representation of one type as an object representation of another type, but this usually makes sense only for types of the same size.

A simple experiment with GCC shows ( https://godbolt.org/z/nphzx- ) that in a non-optimized code your union is stored in memory and changing the value of the c field changes only one byte of memory, but in an optimized code the whole union is stored in the register processor esi and writing the value of the c field overwrites the entire contents of the register, i.e. effectively reset all the "extra" bytes of the union.

    Bits of all fields occupy the same memory.

    Their interpretation depends on the name (type) of the field to which you refer.

    So changing any field at the same time you change all the others.

      How it works?

      Very often, union is used to work with hardware - reading, checking and writing bits to a word. Suppose you are writing a driver for a device that must work with a set of registers of this device, and each register is a collection of a set of bit fields. The easiest way is this:

       union RESISTER_1 { u32 int_value; struct { uint field1 : 1; uint field2 : 7; uint field3 : 1 . . . } bit_fields; } xyz; 

      Then you can read / write the register value using a field of the size of a word ( xyz.int_value ), and work with bits using bit fields ( xyz.bit_fields.field2 ).

        Here is the scheme by which everything is very clear.

         union container { short s; int i; float f; char c; double d; long l; long long ll; }; 

        memory layout:

         container ______________________________ |char| | | short | | | int | | | float | | | double | | long long | | long | | 1 | 2 | 4 | 8 | ______________________________