equality of fields and elements in union - uni_vect.y == uni_vect.v[1]

C

c.a.l

Hi,
I have found a piece of code which declares union like this:
union vector_s {
struct {float x,y,z};
float m[3];
} v;
there is unnamed structure m ( matrix 1x3 ) which has same offset as
x, so they are aligned properly. The problem I have is, whether I can
safely write data to, lets say, v.m[2] and read same data from v.z?
Like:
v.m[2] = 1.25f;
assert (v.z == 1.25f);
I tried to find answer myself, but i was not successfull.
Please, could you enlighten me?
thank you
 
K

Keith Thompson

I have found a piece of code which declares union like this:
union vector_s {
struct {float x,y,z};
float m[3];
} v;

It may be like that, but it's not identical to it, since there are at
least two errors in that declaration. First, a semicolon is required
after ``z'' in the struct declaration. Second, this:

struct {float x,y,z;};

declares an anonyous type, but doesn't declare an object or member of
that type. Some compilers allow anonymous struct members as an
extension, so you could have the above declaration and refer to v.x,
but it's non-standard.

So in standard C you could have:

union vector_s {
struct {float x,y,z;} s;
float m[3];
} v;

and then, rather than v.z, you'd refer to v.s.z.
there is unnamed structure m ( matrix 1x3 ) which has same offset as
x, so they are aligned properly.

m is a one-dimensional array; I wouldn't call it a matrix.
The problem I have is, whether I can
safely write data to, lets say, v.m[2] and read same data from v.z?
Like:
v.m[2] = 1.25f;
assert (v.z == 1.25f);
I tried to find answer myself, but i was not successfull.

It's very likely to work, but it's not guaranteed. The compiler is
allowed to insert padding arbitrarily between struct members, or after
the last member. The only real restrictions are that there can be no
padding at the beginning of a structure, and the members have to be
allocated in their declared order. Array elements, on the other hand,
*must* be allocated consecutively; there can be no padding between
them.

Having said that, it's hard to imagine a compiler inserting padding
between the members of the struct, so what you're doing will almost
certainly work. It's just not *guaranteed* to work -- which means
that it's one more think you'll have to consider if you're tracking
down a bug in the program.

If you really want to be able to access x, y, and z either as array
elements or as struct members, you can play some ugly tricks with the
preprocesor:

union vector_s {
float m[3];
} v;
#define x m[0]
#define y m[1]
#define z m[2]

so ``v.z'' expands to ``v.m[2]''. But a cleaner way to do this is:

enum {x, y, z};
union vector_s {
float m[3];
} v;

which lets you refer to v.m[2] as v.m[z].

(Presumably the real code has better names than m, v, x, y, and z.)
 
F

Flash Gordon

Hi,
I have found a piece of code which declares union like this:
union vector_s {
struct {float x,y,z};
float m[3];
} v;

C does not have anonymous struct/union members so you actually need:
union vector_s {
struct {float x,y,z;} s;
float m[3];
} v;
there is unnamed structure m ( matrix 1x3 ) which has same offset as
x, so they are aligned properly. The problem I have is, whether I can
safely write data to, lets say, v.m[2] and read same data from v.z?
Like:
v.m[2] = 1.25f;
assert (v.z == 1.25f);
I tried to find answer myself, but i was not successfull.
Please, could you enlighten me?

You cannot do it safely since the compiler is allowed to insert padding
between structure members but not between array members. The standard
does not even require that it has a good reason to do it! So whilst
v.m[0] will be at the same address as v.s.x, there is no guarantee that
v.m[1] is at the same address as v.s.y

The correct thing to do is either use an array OR a struct. If you want
to use a struct but still have names you can do
enum {X, Y, Z, NO_ELEMENTS};
float v[NO_ELEMENTS];
Then use v[Z]

Finally, it is almost always better to use double. A lot of the time
floats get promoted to double and where they are different szes float is
often *slower* than double.
 
P

Peter Pichler

I have found a piece of code which declares union like this:
union vector_s {
struct {float x,y,z};
float m[3];
} v;
there is unnamed structure m ( matrix 1x3 ) which has same offset as
x, so they are aligned properly. The problem I have is, whether I can
safely write data to, lets say, v.m[2] and read same data from v.z?
Like:
v.m[2] = 1.25f;
assert (v.z == 1.25f);
I tried to find answer myself, but i was not successfull.

On top of what Keith Thompson and Flash Gordon said, the reason that
your assert fails *might* be that in your implementation, v.z simply
does *not* equal 1.25f (unlikely, since 1.25 is easily representable in
binary, but I take your example as an illustration and 1.25 may in
actual code be a different constant). You can verify it by something like:

float squiggle = 1.25f;
assert(squiggle == 1.25f);

Try:

v.m[2] = 1.25f;
assert(v.z == v.m[2]);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,444
Messages
2,571,709
Members
48,796
Latest member
Greg L.
Top