Reputation: 1653
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
Upvotes: 72
Views: 90641
Reputation: 76611
(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);
Upvotes: 33
Reputation: 1713
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.
Upvotes: 13
Reputation: 574
according to http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields
-fms-extensions
will enable the feature you (and I) want.
Upvotes: 55
Reputation: 23
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. */
Upvotes: -1
Reputation: 8037
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.
Upvotes: 24
Reputation: 1
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.
Upvotes: 0
Reputation: 87541
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.
Upvotes: 0
Reputation: 7886
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.
Upvotes: 3
Reputation:
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));
Upvotes: 2
Reputation: 320797
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.
Upvotes: 8