70

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
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
solinent
  • 1,605
  • 1
  • 17
  • 19
  • 2
    Compile your code again with `-Wall`. GCC should give you warnings about non-portable anonymous structs. – greyfade Dec 29 '09 at 04:04
  • 4
    Even in C++ this is a very bad idea and not guaranteed to work. – sellibitze Dec 29 '09 at 04:06
  • 43
    I wasn't sure where to put this, but anonymous structs and unions are part of the C11 standard. So when the comments below say that this is a nonstandard GNU extension, that's now outdated. – bk. Feb 03 '12 at 19:50
  • 9
    @sellibitze What are you talking about? This is not a bad idea in principle. He's simply creating a union and inside the union placing a struct and an array. He wants them to be anonymous to reduce the length of member access. – bobobobo Feb 24 '12 at 16:51
  • @solinent Just 2 comments: You don't need the outer struct (you should write `union vec3 { ... }`), and you should probably name the `xyz` member something _other_ than `xyz`. Something like `e` or `comps` works fine. – bobobobo Feb 24 '12 at 16:53
  • @bobobobo I like to think of `xyz` as a swizzle access, ala GLSL, even if it doesn't make an incredible amount of sense. I probably would use `data` nowadays, though. I use C++ primarily, so I would avoid this whole thing and use a function which returns a reference to the data member nowadays, and a `operator[]` for indexed access. – solinent Feb 28 '12 at 15:14

10 Answers10

54

according to http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields

-fms-extensions will enable the feature you (and I) want.

unkulunkulu
  • 11,576
  • 2
  • 31
  • 49
user287561
  • 564
  • 5
  • 2
33

(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);
R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
25

The new C11 standard will support anonymous structures and unions, see foreword paragraph 6 of the April 2011 draft.

http://en.wikipedia.org/wiki/C1X

The strange part is that both gcc and clang now support anonymous structures and unions in C89 and C99 mode. In my machine no warnings appear.

hdante
  • 7,685
  • 3
  • 31
  • 36
13

One can also always do the following:

typedef struct
{
    float xyz[0];
    float x, y, z;
}Vec3;

The zero-length array doesn't allocate any storage, and just tells C to "point to whatever the next thing declared is." Then, you can access it just like any other array:

int main(int argc, char** argv)
{
    Vec3 tVec;
    for(int i = 0; i < 3; ++i)
    {
        tVec.xyz[i] = (float)i;
    }

    printf("vec.x == %f\n", tVec.x);
    printf("vec.y == %f\n", tVec.y);
    printf("vec.z == %f\n", tVec.z);

    return 0;
}

Result:

vec.x == 0.000000
vec.y == 1.000000
vec.z == 2.000000

If you want to be extra paranoid, you can manually specify the data packing strategy to suit your platform.

Ionoclast Brigham
  • 1,703
  • 1
  • 12
  • 19
  • 1
    Very creative, but my compiler (VS120) complains that zero-sized arrays are a non-standard extension too. Each other compiler should also warn or not compile this code. – Johannes Jendersie Jul 03 '14 at 07:56
  • If you compile with the switch '-std=gnuXX' in gcc or clang, this won't be an error or warning, as you are telling the compiler you acknowledge that it's an extension. But yes, in fully standards-compliant C code, I would instead just go with a union. – Ionoclast Brigham Jul 05 '14 at 20:37
  • 1
    C99 supports variable size arrays, so in case of C99 (-std=c99) just declare as float[] and no need for struct hack any more. – Alex Oct 19 '15 at 15:20
  • 4
    Actually, I was lying. If you change float[0] (gnu99) to float[] (c99) - it won't compile, since the variable-array MUST be at the end of the struct, where it does not make any sense in this case. So float[0] it is. – Alex Nov 27 '15 at 20:49
8

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    as a sidenote, gcc does support this as an extension, you'll have run gcc in non standard C mode though(the default), or explicittly use -std=gnu99 or similar. – nos Dec 28 '09 at 23:19
  • Yes, I know this, and should have mentioned it. It just makes the code look better, and is not hard to fix if it was unportable. In this case, I'm simply writing it for my own use, so it's not a problem. (I'm writing a c raytracer to learn the intricacies of c) – solinent Dec 29 '09 at 19:46
3

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.

Afriza N. Arief
  • 7,696
  • 5
  • 47
  • 74
  • Still uses extensions. Enter `-pedantic` in the command line: "main.cpp:7: warning: ISO C++ prohibits anonymous structs main.cpp:14: warning: ISO C++ prohibits anonymous structs" – GManNickG Jan 29 '10 at 19:10
  • 2
    well, the question is about GCC, not ISO C++ .. good to know what ISO C++ says though.. ; P – Afriza N. Arief Jan 30 '10 at 06:19
2

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));
  • 3
    The standard says that when a member of a union is assigned, the value of the other members is **unspecified**. It also says that the bit representation is shared among the members. This is not undefined behavior. It seems quite clearly defined. – greyfade Dec 29 '09 at 04:24
  • The Standard says "When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values." But that does not mean that the value of other members may not be a trap (their compound bytes are not, merely). It says "The value of a structure or union object is never a trap representation, even though the value of a member of the structure or union object may be a trap representation.". Reading from a different member is not undefined behavior per se, but it may. – Johannes Schaub - litb Dec 30 '09 at 01:23
  • 1
    .. It may if we read a trap representation and then behavior is undefined, as it says in a foot-note (nonnormative) most clearly: "If the member used to access 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.". – Johannes Schaub - litb Dec 30 '09 at 01:25
0

The GNU dialect of C supports anonymous structs/unions, but by default GCC compiles using some kind of standard C. To use the GNU dialect, put "-std=gnu99" on the command line.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
0

Unidentified struct members not being ANSI/ISO C99 standard explains this, but I find a funny thing happens, on some ports of GNU C Compiler 2.x.x versions, using undentified struct members works, it finds them, doesn't say stuff like "x is not a member of union\struct y, what is x?", other times, it's the ol' "x is undefined", "x is not a member of struct", hell I swear I saw a "pointer to unknown" once a while back, due to this.

So I, professionally would go with everyone else on this and just ether give the struct\union member a identifier, or in the case of UNIONs, carefully rearrange the code so the union ends up an identified member of a identified structure and the members that were embedded in the unidentified structure of the original union, become members of the identified structure and are carefully used with the identified union member. But in those cases were the latter method would not be a workable substitute, I would just give the annoynous structure an identifier and move on.

DLCJ
  • 1
-1

I can suggest an interesting workaround in order to avoid too much fields within the structure. One is advised to warn about simply named defines, as it could create conflicts.

#define x    ___fl_fld[0]
#define y    ___fl_fld[1]
#define z    ___fl_fld[2]
#define w    ___fl_fld[3]
#define r    ___fl_fld[0]
#define g    ___fl_fld[1]
#define b    ___fl_fld[2]
#define a    ___fl_fld[3]
typedef union {
    float ___fl_fld[4];
    float xyz[3];
    float rgb[3];
} Vector3;

You could access the structure like this:

Vector3 v;
assert(&v.x == &v.r); //Should return true

To finish, this would be a multi type union compatible with C99:

#define u8llsb __u8[0]
#define u8lmsb __u8[1]
#define u8mlsb __u8[2]
#define u8mmsb __u8[3]
#define u16lsb __u16[0]
#define u16msb __u16[1]
#define u16    __u16[0]
#define u8lsb  __u8[0]
#define u8msb  __u8[1]

typedef union {
    uint32_t u32;
    int32_t  i32;
    uint16_t  __u16[2];
    uint8_t   __u8[4];
} multitype_t;

multitype_t Var;
var.u32;
var.i32;
var.u8llsb;
/* etc. */
  • I can only imagine the amazing compiler errors that would ensue after `#define`ing all your single-character variable names into `__fl_fld[2]`. – StilesCrisis Sep 19 '14 at 22:00
  • Bit to readable for the obfuscated code contest, and *way* to generic names for the defines in anything *but* obfuscated code contest entries... – fgp Oct 22 '14 at 00:46
  • This is why many coding standards discourage or prohibit the use of macros. Personnally, I think preprocessor macros get a bad rap. If sensibly used, they can greatly improve code quality. But the problem here is that you are polluting the global namespace. If anyone included a header file containing these #definitions, and they happened to have a variable named "x" or "y", etc. anywhere, you have broken their code. – Die in Sente Nov 08 '16 at 16:52