How to compile C code with anonymous structs / unions?

Viewed 86332

I can do this in c++/g++:

struct vec3 { 
    union {
        struct {
            float x, y, z;
        }; 
        float xyz[3];
    }; 
};

Then,

vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);

will work.

How does one do this in c with gcc? I have

typedef struct {
    union {
        struct {
            float x, y, z;
        };
        float xyz[3];
    };
} Vector3;

But I get errors all around, specifically

line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything
10 Answers

(This answer applies to C99, not C11).

C99 does not have anonymous structures or unions. You have to name them:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

And then you have to use the name when accessing them:

assert(&v.data.xyz[0] == &v.data.individual.x);

In this case, because your top level structure has a single item of type union, you could simplify this:

typedef union {
    struct {
        float x, y, z;
    } individual;
    float xyz[3];
} Vector3;

and accessing the data now becomes:

assert(&v.xyz[0] == &v.individual.x);

Anonymous unions is a feature of C++ language. C language has no anonymous unions.

Anonymous structs don't exist in neither C nor C++.

The declaration you presented in your question might compile with GCC C++ complier, but it would be just a compiler-specific extension, which has nothing to do with neither standard C nor standard C++.

On top of that, regardless of how you implement it, neither C nor C++ language guarantees that your assertions will hold.

I can do this in GCC without warning

typedef union {
    struct { // human-friendly access
        float x;
        float y;
        float z;
        float w;
    };
    float xyz[3];
    struct { // human-friendly access
        float r;
        float g;
        float b;
        float a;
    };
    float rgb[3];
} Vector4f;

int main()
{
    Vector4f position, normal, color;
    // human-friendly access
    position.x = 12.3f;
    position.y = 2.f;
    position.z = 3.f;
    position.w = 1.f;

    normal.x = .8f;
    normal.y = .9f;
    normal.z = .1f;
    normal.w = 1.f;

    color.r = 1.f;
    color.g = .233f;
    color.b = 2.11f;
    color.a = 1.1f;

    // computer friendly access
    //some_processor_specific_operation(position.vec,normal.vec);
    return 0;
}

C:\>gcc vec.c -Wall

C:\>gcc --version gcc (GCC) 4.4.0 Copyright (C) 2009 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Anonymouse unions are nor supported in C.

Also note that if you declare it this way:

typedef struct {
    union {
        struct {
            float x, y, z;
        } individual;
        float xyz[3];
    } data;
} Vector3;

Doing

Vector3 v;
v.data.xyz[0] = 5;

float foo = v.data.individual.x;

Is an undefined behaviour. You can only access the last assigned union member. In your case, using an union is wrong and bad coding practice as it's dependent on many things that are not specified in the standard (padding...).

In C you will prefer something like this:

typedef struct {
    float v[3];
} Vec3;

And if you don't want to use v[x] you might consider:

#define X(V) ((V).v[0])

Vec3 v;
X(v) = 5.3;
printf("%f\n", X(v));
Related