Unions in structures

M

Morris Dovey

blockstack said:
I recently noticed (I'm new to the language) that when using a union
type as a component of a structure, you don't need a union-tag.

struct foo
{
char *ptr;
union
{
int i;
float f;
char c;
};
};

I have never read that a union type reference is optional in any
case.
Is this specific to the compiler, or part of the standard?

A footnote to Eric's response:

This convention produces headaches when/if struct foo is expanded
to:

struct foo
{ char *ptr;
unsigned i;
union
{ int i;
float f;
char c;
};
};

struct foo x;
x.i = 7; /* Which i in x? */
 
B

blockstack

I recently noticed (I'm new to the language) that when using a union
type as a component of a structure, you don't need a union-tag.

struct foo
{
char *ptr;
union
{
int i;
float f;
char c;
};
};

I have never read that a union type reference is optional in any
case.
Is this specific to the compiler, or part of the standard?
 
E

Eric Sosman

blockstack said:
I recently noticed (I'm new to the language) that when using a union
type as a component of a structure, you don't need a union-tag.

struct foo
{
char *ptr;
union
{
int i;
float f;
char c;
};
};

I have never read that a union type reference is optional in any
case.
Is this specific to the compiler, or part of the standard?

A union does not need to have a union tag, and a struct
does not need to have a struct tag. But I think you may be
mixing up the terminology!

- A "struct tag" is an identifier that can be combined
with the keyword `struct' to form a name for a specific
struct type. In your example, `foo' is a struct tag
and `struct foo' is the name of the type. If the `foo'
were absent, the struct would have no tag and there
would be no way to write a name for its type elsewhere
in the program.

- Similarly, a "union tag" is an identifier that can be
combined with the keyword `union' to form a name for a
specific union type. In your example, the union has no
tag and there is no way to write the name of the union's
type. If the identifier `bar' appeared right after the
`union' keyword, `bar' would be the union tag and
`union bar' would be the name of the type.

- Almost every element contained in a struct or union (the
lone exception is not important here) must have an element
name. In your example, `i', `f', and `c' are the names
of the elements of the union. `ptr' is the name of one
element of the struct, but the other element (the union)
has no name. This is a compile-time error for which the
compiler is required to produce a diagnostic message.

So, why do you get no error message? Probably because you
are not using a C compiler, but a C-with-extras compiler that
accepts a C-like language that isn't really C. The gcc compiler
is like that in its default mode of operation; command-line flags
like `-ansi -pedantic' can make it conform more strictly to the
actual definition of C.
 
B

blockstack

A union does not need to have a union tag, and a struct
does not need to have a struct tag. But I think you may be
mixing up the terminology!

- A "struct tag" is an identifier that can be combined
with the keyword `struct' to form a name for a specific
struct type. In your example, `foo' is a struct tag
and `struct foo' is the name of the type. If the `foo'
were absent, the struct would have no tag and there
would be no way to write a name for its type elsewhere
in the program.

- Similarly, a "union tag" is an identifier that can be
combined with the keyword `union' to form a name for a
specific union type. In your example, the union has no
tag and there is no way to write the name of the union's
type. If the identifier `bar' appeared right after the
`union' keyword, `bar' would be the union tag and
`union bar' would be the name of the type.

- Almost every element contained in a struct or union (the
lone exception is not important here) must have an element
name. In your example, `i', `f', and `c' are the names
of the elements of the union. `ptr' is the name of one
element of the struct, but the other element (the union)
has no name. This is a compile-time error for which the
compiler is required to produce a diagnostic message.

So, why do you get no error message? Probably because you
are not using a C compiler, but a C-with-extras compiler that
accepts a C-like language that isn't really C. The gcc compiler
is like that in its default mode of operation; command-line flags
like `-ansi -pedantic' can make it conform more strictly to the
actual definition of C.

Thanks,
Using the option --ansi=pedantic did cause an error. I used union-tag
and union-type-reference synonymously as I thought both were
identifiers, but I see how I needed to make the distinction.
The reason I was asking was because I was reading an old K&R C book
from the 80s in which they were describing the previous code as a
union variation rather than a structure. And then I received no error,
so I wondered if this was part of the standard.
But it is not standard C. It does seem to make things easier though.
 
K

Keith Thompson

blockstack said:
I recently noticed (I'm new to the language) that when using a union
type as a component of a structure, you don't need a union-tag.

struct foo
{
char *ptr;
union
{
int i;
float f;
char c;
};
};

I have never read that a union type reference is optional in any
case.
Is this specific to the compiler, or part of the standard?

It's specific to the compiler. As far as the standard is concerned,
the above is an error requiring a diagnostic. Some compilers allow
anonymous unions as an extension.

In particular, gcc supports this. gcc's "-pedantic" option will cause
it to issue a warning.
 
E

Eric Sosman

[concerning a struct containing a union element with no identifier]
[...] And then I received no error,
so I wondered if this was part of the standard.
But it is not standard C. It does seem to make things easier though.

It can be handy, and several compilers allow it as an
extension to Standard C. The uses I've seen, though, have
all been of a somewhat dubious nature, along the lines of

struct thing {
struct {
unsigned int readyFlag : 1;
unsigned int willingFlag : 1;
unsigned int ableFlag : 1;
}; /* no name */
unsigned int flags;
#define READY_FLAG 0x1
#define WILLING_FLAG 0x2
#define ABLE_FLAG 0x4
};

The idea is that you can access the flags individually:

struct thing x;
x.readyFlag = 1;
x.willingFlag = 0;
x.ableFlag = 1;

.... or en masse:

struct thing y;
y.flags = READY_FLAG | ABLE_FLAG;

The "dubious" part here is that the compiler has a lot
of freedom in how it arranges the bit fields in a struct.
On some compilers (that allow no-name elements), the code
above may work as intended. But on others, the macro
values should be 0x80000000, 0x40000000, and 0x20000000,
or maybe 0x01000000, 0x00010000, and 0x00000100, or maybe
something else altogether. So it *looks* like a convenient
dodge, but may wind up relying on the internals of the
compiler. The result certainly isn't portable, not even
portable among compilers allowing no-name elements.
 
B

Ben Pfaff

Eric Sosman said:
The uses I've seen, though, have
all been of a somewhat dubious nature, along the lines of

struct thing {
struct {
unsigned int readyFlag : 1;
unsigned int willingFlag : 1;
unsigned int ableFlag : 1;
}; /* no name */
unsigned int flags;
#define READY_FLAG 0x1
#define WILLING_FLAG 0x2
#define ABLE_FLAG 0x4
};

I think that "struct thing" should be "union thing".
 
S

Serve Laurijssen

Eric Sosman said:
Age has not withered nor custom staled the correctness
of your thought. Thanks.

I somehow get the urge to print this out in big letters and hang it on the
wall. But eh what does it mean?

(literally)
 

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

Similar Threads


Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top