Difference between a Structure and a Union

Viewed 381193

Is there any good example to give the difference between a struct and a union? Basically I know that struct uses all the memory of its member and union uses the largest members memory space. Is there any other OS level difference?

17 Answers

With a union, you're only supposed to use one of the elements, because they're all stored at the same spot. This makes it useful when you want to store something that could be one of several types. A struct, on the other hand, has a separate memory location for each of its elements and they all can be used at once.

To give a concrete example of their use, I was working on a Scheme interpreter a little while ago and I was essentially overlaying the Scheme data types onto the C data types. This involved storing in a struct an enum indicating the type of value and a union to store that value.

union foo {
  int a;   // can't use both a and b at once
  char b;
} foo;

struct bar {
  int a;   // can use both a and b simultaneously
  char b;
} bar;

union foo x;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!

struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK

edit: If you're wondering what setting x.b to 'c' changes the value of x.a to, technically speaking it's undefined. On most modern machines a char is 1 byte and an int is 4 bytes, so giving x.b the value 'c' also gives the first byte of x.a that same value:

union foo x;
x.a = 3;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

prints

99, 99

Why are the two values the same? Because the last 3 bytes of the int 3 are all zero, so it's also read as 99. If we put in a larger number for x.a, you'll see that this is not always the case:

union foo x;
x.a = 387439;
x.b = 'c';
printf("%i, %i\n", x.a, x.b);

prints

387427, 99

To get a closer look at the actual memory values, let's set and print out the values in hex:

union foo x;
x.a = 0xDEADBEEF;
x.b = 0x22;
printf("%x, %x\n", x.a, x.b);

prints

deadbe22, 22

You can clearly see where the 0x22 overwrote the 0xEF.

BUT

In C, the order of bytes in an int are not defined. This program overwrote the 0xEF with 0x22 on my Mac, but there are other platforms where it would overwrite the 0xDE instead because the order of the bytes that make up the int were reversed. Therefore, when writing a program, you should never rely on the behavior of overwriting specific data in a union because it's not portable.

For more reading on the ordering of bytes, check out endianness.

Here's the short answer: a struct is a record structure: each element in the struct allocates new space. So, a struct like

struct foobarbazquux_t {
    int foo;
    long bar;
    double baz; 
    long double quux;
}

allocates at least (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) bytes in memory for each instance. ("At least" because architecture alignment constraints may force the compiler to pad the struct.)

On the other hand,

union foobarbazquux_u {
    int foo;
    long bar;
    double baz; 
    long double quux;
}

allocates one chunk of memory and gives it four aliases. So sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)), again with the possibility of some addition for alignments.

Is there any good example to give the difference between a 'struct' and a 'union'?

An imaginary communications protocol

struct packetheader {
   int sourceaddress;
   int destaddress;
   int messagetype;
   union request {
       char fourcc[4];
       int requestnumber;
   };
};

In this imaginary protocol, it has been sepecified that, based on the "message type", the following location in the header will either be a request number, or a four character code, but not both. In short, unions allow for the same storage location to represent more than one data type, where it is guaranteed that you will only want to store one of the types of data at any one time.

Unions are largely a low-level detail based in C's heritage as a system programming language, where "overlapping" storage locations are sometimes used in this way. You can sometimes use unions to save memory where you have a data structure where only one of several types will be saved at one time.

In general, the OS doesn't care or know about structs and unions -- they are both simply blocks of memory to it. A struct is a block of memory that stores several data objects, where those objects don't overlap. A union is a block of memory that stores several data objects, but has only storage for the largest of these, and thus can only store one of the data objects at any one time.

As you already state in your question, the main difference between union and struct is that union members overlay the memory of each other so that the sizeof of a union is the one , while struct members are laid out one after each other (with optional padding in between). Also an union is large enough to contain all its members, and have an alignment that fits all its members. So let's say int can only be stored at 2 byte addresses and is 2 bytes wide, and long can only be stored at 4 byte addresses and is 4 bytes long. The following union

union test {
    int a;
    long b;
}; 

could have a sizeof of 4, and an alignment requirement of 4. Both an union and a struct can have padding at the end, but not at their beginning. Writing to a struct changes only the value of the member written to. Writing to a member of an union will render the value of all other members invalid. You cannot access them if you haven't written to them before, otherwise the behavior is undefined. GCC provides as an extension that you can actually read from members of an union, even though you haven't written to them most recently. For an Operation System, it doesn't have to matter whether a user program writes to an union or to a structure. This actually is only an issue of the compiler.

Another important property of union and struct is, they allow that a pointer to them can point to types of any of its members. So the following is valid:

struct test {
    int a;
    double b;
} * some_test_pointer;

some_test_pointer can point to int* or double*. If you cast an address of type test to int*, it will point to its first member, a, actually. The same is true for an union too. Thus, because an union will always have the right alignment, you can use an union to make pointing to some type valid:

union a {
    int a;
    double b;
};

That union will actually be able to point to an int, and a double:

union a * v = (union a*)some_int_pointer;
*some_int_pointer = 5;
v->a = 10;
return *some_int_pointer;    

is actually valid, as stated by the C99 standard:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

  • a type compatible with the effective type of the object
  • ...
  • an aggregate or union type that includes one of the aforementioned types among its members

The compiler won't optimize out the v->a = 10; as it could affect the value of *some_int_pointer (and the function will return 10 instead of 5).

"union" and "struct" are constructs of the C language. Talking of an "OS level" difference between them is inappropriate, since it's the compiler that produces different code if you use one or another keyword.

You have it, that's all. But so, basically, what's the point of unions?

You can put in the same location content of different types. You have to know the type of what you have stored in the union (so often you put it in a struct with a type tag...).

Why is this important? Not really for space gains. Yes, you can gain some bits or do some padding, but that's not the main point anymore.

It's for type safety, it enables you to do some kind of 'dynamic typing': the compiler knows that your content may have different meanings and the precise meaning of how your interpret it is up to you at run-time. If you have a pointer that can point to different types, you MUST use a union, otherwise you code may be incorrect due to aliasing problems (the compiler says to itself "oh, only this pointer can point to this type, so I can optimize out those accesses...", and bad things can happen).

A structure allocates the total size of all elements in it.

A union only allocates as much memory as its largest member requires.

Unions come handy while writing a byte ordering function which is given below. It's not possible with structs.

int main(int argc, char **argv) {
    union {
        short   s;
        char    c[sizeof(short)];
    } un;

    un.s = 0x0102;

    if (sizeof(short) == 2) {
        if (un.c[0] == 1 && un.c[1] == 2)
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)
            printf("little-endian\n");
        else
            printf("unknown\n");
    } else
        printf("sizeof(short) = %d\n", sizeof(short));

    exit(0);
}
// Program from Unix Network Programming Vol. 1 by Stevens.

A Union is different from a struct as a Union repeats over the others: it redefines the same memory whilst the struct defines one after the other with no overlaps or redefinitions.

It is recommended to use structures when we need to model something which has a group of independent attributes and unions should be used when an entity has many forms and it can exist in only one form at a time.

Let us look at 2 places where they could be applied

You need to store and update values of a car. In order to do so we need to record all the attributes of a car like model, mileage, price and fuel type. These values are always present in a car and they do not depend on other values. Hence we require a data type that not only stores all our attributes but also ensures their proper updation. Such types of tasks can be done using structures.

struct car{
    char model[];
    int mileage;
    int price;
    char fuel_type[];
};

An organization needs to collect your data for payment verification from a large number of customers. Now for data integrity and customer security an organization is directed to take the least number of details from a person. These details can be either your PAN number or account number or voter id. Now since we need to collect any one of these details and also be memory efficient at the same time we can use union here. It will hold only the single value that is provided to it.

union verification_details{
    char account_number[10];
    char PAN[10];
    char voter_id[10];
};

I found the following article that explains it quite well: Difference Between Structure and Union

Is there any good example to give the difference between a struct and a union?

Real-life example from embedded system application would be the following. It only uses union but it clearly shows the functionality of union.

Write function for I2C communication protocol uses union type, which is used for data storage, when retrieving data from array passed to it.

union data
{
    uint32_t packet;
    uint8_t  packetbyte[4];
} txdata;

Array being passed to the write function via pointer contains elements of a size of one byte. In for loop these bytes are extracted one by one in four steps and stored into individual elements of txdata.packetbyte member.

After end of loop, txdata.packet holds 4 bytes of data, which were being consecutively stored into txdata union. And as final step of sending data over communication bus, txdata.packet is written into 32-bit buffer, which initiates write sequence after being written to. Then reset content by txdata.packet = 0 before next for loop starts executing.

This way I2C master can re-transmit 32-bit packets until passed input data is sent and write function is terminated.

Related