Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union of structs with common first member

Tags:

c

struct

unions

I am unsure of whether or not the code has pointer aliasing (or other standard conformance issues) in the asserts cast. It seems that a pointer to the union type should be able to be cast to a pointer of the first member and since the union is only composed of these two structs, I think a cast to the first member should work, but I'm not sure if this is correct or if I'm glossing over padding details in the process. Are unions required to pad the upper bits?

It seems as this is unspecified behavior? Does anyone have any insight as to whether this is suported. I know that there is an alternative standard way of doing this by using a struct with a enum type field and struct container_storage member, but it seems like a waste of space considering that this information is already in struct contained

compilation command in linux: gcc -std=c99 -Wextra -pedantic -fstrict-aliasing test.c && ./a.out && echo $? returns 0

#include <stdlib.h>
#include <assert.h>

enum type {type_a = 1, type_b = 2};

struct contained {
    int some_other_field;
    enum type type;
};

struct container_a {
    struct contained contained;
    int test;
};


struct container_b {
    struct contained contained;
    char test;
};

union container_storage {
    struct container_a container_a;
    struct container_b container_b;
};

int
main(int argc, char **argv)
{
    union container_storage a =
        {.container_a = {.contained = {.type = type_a}, .test = 42}};
    union container_storage b =
        {.container_b = {.contained = {.type = type_b}, .test = 'b'}};

    assert(((struct contained *)&a)->type == type_a);
    assert(((struct contained *)&b)->type == type_b);

    return EXIT_SUCCESS;
}

References:

[1] gcc, strict-aliasing, and casting through a union

[2] What is the strict aliasing rule?

like image 994
backscattered Avatar asked Dec 23 '13 22:12

backscattered


2 Answers

That should be fine. C11, 6.5.2.3/6 ("Structure and union members") says:

One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

(C++ makes the same guarantee (C++11, 9.2/18) for standard-layout unions.)

like image 193
Kerrek SB Avatar answered Sep 20 '22 01:09

Kerrek SB


union don't pad, they just overlay their members. The first member of any struct is guaranteed to start right off, without padding. In general struct that start with the same members of same type are guaranteed to have the same layout for that initial part.

like image 35
Jens Gustedt Avatar answered Sep 19 '22 01:09

Jens Gustedt