Accessing first field of struct in a union of structs - c

I have three structs that share the first type and name of the first field:
struct TYPEA {
char *name;
int x,y; /*or whatever*/
};
struct TYPEB {
char *name;
float a[30]; /*or whatever*/
};
struct TYPEC {
char *name;
void *w,*z; /*or whatever*/
};
If I remember correctly the first field of a struct is required to start at the same address as the struct itself.
This makes me wonder if the same holds for a union:
union data {
struct TYPEA;
struct TYPEB;
struct TYPEC;
};
union data *p = function_returning_a_sane_default_for_union_data();
printf("%s", (char*) p);
I have 2 question regarding this:
are unions required by standard
to always have their content at the same address?
would it work if the structs all had the same
fiels, so differing only in name?

The first element of a struct or union is guaranteed to have the same address-value as the struct´/union itself. Apparently it has not the same type!
For your usage, you do not need the cast and actually should avoid it:
6.5.2.3p6: One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. …
So you could (see below) simply
printf("%s", p->name);
(Note: that your usage of unnamed union members is not standard compilant. It is a (very useful) gcc extension (-fms-extensions, at least also supported by MSVC, too).)
But: The code in your question is wrong. You have to name each union member or have the type declarator with each member. With the same first member, It will not weork, though, because the names of the mebers of such unnamed members have to be unique (how else are they supposed to be accesseed individually?). So this will not really work. What you could do is:
union data {
struct TYPEA typea;
struct TYPEB typeb;
struct TYPEC typec;
};
and
printf("%s", p->typea.name);
even if the struct contains a value of TYPEB currently.
An alternative and more clear way, would be to wrap the union into a struct:
struct TypeA {
int x,y;
};
...
struct data {
char *name;
union {
struct TypeA;
struct TypeB;
struct TypeC;
};
};
This also uses the gcc extension at two levels: for the outer struct and the union. As such, it requires unique names for all possible paths. If you want to be 100% compliant, name each member like above and use the full path on access.
Note: I removed the name member from the inner structs in the union and moved it to the outer struct. I also changed names. The only well accepted naming convention in C is to use all-uppercase for macros only.

Related

Opaque structure with flexible array member

Suppose I have a struct declaration in a header file like:
event.h
struct event_t;
and in the corresponding C file I would like to sort-of alias it with the Linux-specific struct inotify_event. The problem is that struct inotify_event contains flexible array member:
struct inotify_event {
int wd;
uint32_t mask;
uint32_t cookie;
uint32_t len;
char name[];
};
As per 6.7.2.1(p3) (emphasize mine):
A structure or union shall not contain a member with incomplete or
function type (hence, a structure shall not contain an instance of
itself, but may contain a pointer to an instance of itself), except
that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union
containing, possibly recursively, a member that is such a structure)
shall not be a member of a structure or an element of an array.
it is not possible to define the struct event_t as
struct event_t{
struct inotify_event base; //Non-conforming
};
So I could convert struct event_t * to struct inotify_event *. Since the 6.7.2.1(p3) concerns only about structs the solution I see is to redeclare the tag name as
union event_t
and then define it later as a single element union.
union event_t{
struct inotify_event event; //Conforming?
};
The only requirement the Standard imposes on union that I found is that the set of members of a union must be non-empty 6.2.5(p20) (emphasize mine):
A union type describes an overlapping nonempty set of member objects,
each of which has an optionally specified name and possibly distinct
type.
QUESTION: Is it a conforming/common way to hide an implementation details of some specific data structure through union?
This is how I would do it:
event.h
struct event_t;
event_t *create_event(void);
void free_event(event_t *ev);
event.c
#include "event.h";
event_t *create_event(void)
{
inotify_event *iev = ...;
return (event_t *)iev;
}
void free_event(event_t *ev)
{
inotify_event *iev = (inotify_event *)ev;
// free the event
}
However, if you want to store additional data with the event then:
event.h
struct event_t;
event_t *create_event(void);
void free_event(event_t *ev);
event.c
#include "event.h";
struct event_t
{
inotify_event *iev;
// additional data
};
event_t *create_event(void)
{
inotify_event *iev = ...;
event_t *ev = malloc(sizeof(event_t));
ev.iev = iev;
return ev;
}
void free_event(event_t *ev)
{
inotify_event *iev = (inotify_event *)ev.iev;
// free the event (iev) first
free(ev);
}
If you have multiple implementations that you need to hide in event_t then:
enum event_type
{
EVENT_TYPE_INOTIFY,
EVENT_TYPE_INOTIFY2,
};
struct event_t
{
event_type type;
union {
inotify_event *iev; // you use this when type == EVENT_TYPE_INOTIFY
inotify_event2 *iev2; // you use this when type == EVENT_TYPE_INOTIFY2
}
// additional data
};
By far the simplest technique is to put this into your event.h header:
typedef struct inotify_event event_t;
This declares that there is a structure type struct inotify_event and declares an alias for it event_t. But it does not define the content of struct inotify_event at all.
Only the implementation code in event.c includes the definition of struct inotify_event from the system header; everything else does not include that header and cannot access the elements of an event_t except through the accessor API you define.
You can enforce this separation of duties by code review — or by checking with grep, or other similar techniques — to ensure that no code except the implementation of your event type uses the system header for inotify_event. And, if you port to a system other than Linux without support for inotify, then you simply provide an alternative opaque structure type in place of struct inotify_event in your event.h header.
This avoids all questions about whether there are flexible array members within structures, etc; it is all a non-issue.
Note the Q&A about What does a type followed by _t (underscore t) represent? . Be cautious about creating your own types with the _t suffix ¸— consider using a prefix on such type names that gives you a chance that your names will be distinct from those provided by the system.
Single element union makes no sense. The purpose of union is to serve as a kind of polymorphic struct. struct members are accessed by offset, this is why is impossible to put an incomplete struct or array in the middle of a struct.
For example
struct foo { int a; int b[]; int c; };
In this example is impossible for the compiler to determine the address of c because b size can vary at runtime. But if you put incomplete array at the end all struct members address can be determined by the address of the start of the struct. Keep in mind that pointers are just address, so you can have any pointers to any structs and all the offsets can be determined, but you will need to deal with extra alloc/free stuff.
When you create an union you telling to compiler Hey! I have this members, reserve enough space for me so that I can treat this variable as foo or bar. In another words, the compiler will take the largest union member and this will be the size of the union. A common use for union is for representing multiple kinds of values.
typedef union { int integer, float real, char *string } value_type;
This way you can treat value_type as int, float, or a char pointer. You're code need to know the how to treat each member but the compiler will make sure that when you do malloc(sizeof value_type) you have enough space for the tree types.
Now your problem. You want to hide implementation details. Usually this is done by declaring a type or struct incompletely in a header, and completely only on your object files. Because of this when the user include your header all the information that the compiler has is struct my_struct;. It can't tell the size of my_struct so is impossible for you to allocate it as malloc(sizeof struct my_struct). Also since the user hasn't the member definitions it can't mess up with the struct internals.
Working like this you will need to provide user with functions for allocating and freeing my_struct, for example struct my_struct *foo = my_struct_new() and my_struct_destroy(foo).
You're already doing this. To deal with the struct inotify problem I would do one of these.
(1) Surround OS specific with #ifdef for that OS, so that the event_t has only the right members defined depending on the operating system. You will need #ifdef on your functions. This has the advantage to keep useless code out of final binary, so smaller footprint.
(2) Have pointers to OS specific structs and let runtime decide what to do. This easier to maintain.

how to determine what type of the union is used when output?

I used a union type in the struct to define whether this person is a student or a staff. When i tried to output the information in the struct array, i found it was hard for me to figure out what kind of this person was ,not to say output the further information. Do not tell me stop using union, sorry, i was asked to do so.
Hers's my simplified data structure:
typedef union student_or_staff{
char *program_name;
char *room_num;
}student_or_staff;
typedef struct people{
char *names;
int age;
student_or_staff s_or_s;
}people[7];
The only way to know what is stored in a union is to include this information in some other place.
There are two common situations that happen when you deal with an array of unions (or structs that hold a union):
All unions in an array hold the same type, or
Each union may hold its own type.
When all unions in an array hold the same type, a single variable that indicates the type the unions hold is sufficient.
When each union could hold a different type, a common approach is to wrap it in a struct, and add a flag indicating which way the union is set. Using your example, the flag should be added to struct people, like this:
enum student_staff_flag {
student_flag
, staff_flag
};
typedef struct people{
char *names;
int age;
enum student_staff_flag s_or_s_flag;
student_or_staff s_or_s;
}people[7];
It is not possible to do this in C but as a workaround you can add a type along your union like this
enum { student_type, staff_type } PEOPLE_TYPE;
typedef union student_or_staff{
char *program_name;
char *room_num;
}student_or_staff;
typedef struct people{
char *names;
int age;
student_or_staff s_or_s;
PEOPLE_TYPE people_type;
}people[7];
Then you just set that along with your union when you assign your struct.

Handling incomplete type errors in C

I have a struct called 'residence' below. It contains a person_list struct where the person_list struct contains a struct for each person.
typedef struct a_person
{
char name [MAX_LENGTH];
int age;
} person;
typedef struct person_list
{
struct person people[MAX_ALLOWED];
} personList;
struct residence {
char residence_name [MAX_LENGTH];
struct personList resident_list;
};
I'm getting these errors upon compilation:
error: resident_list; has incomplete type
error: array type has incomplete element type (#struct person
people[MAX_ALLOWED];)
If you need additional code or information please don't hesitate to ask
You could predeclare every struct that you are further defining, e.g. by starting your file (or your header file) with
struct a_person; // should be person_st
struct person_list; // should be person_list_st
then you may have a pointer to such struct (even without having defined the fields of that struct yet).
However, when you define a struct by listing all its fields, every field should have a size known to the compiler.
Some further hints (including conventions):
you could (and I do, conventionally) name every struct tag ending with e.g. _st (this is a convention that I do like to follow)
you can make a typedef together with the struct declaration, e.g.
typedef struct a_person_st Person;
BTW, I am following the convention (inspired by GTK) that a structure type starts with a capital letter.
I don't recommend having typedef for pointers. Being a pointer type is really important in C, and I feel it should be kept apparent. So I recommend against typedef Person*PersonPtr; (but again, this is my convention).
You would later define the struct by listing its fields, e.g.
struct person_st { // or Person
char name[MAX_LENGTH];
int age;
}; // end of definition of struct person_st
You might be interested (assuming a C99 or C11 compiler) by flexible array members (it is a C feature, not a C++ one, and that flexible array member should always be the last of its containing struct).

Nameless union inside a union

I'm reading some code and found something like the following:
typedef union {
int int32;
int boolean;
time_t date;
char *string;
union {
struct foo *a;
struct foo *b;
struct foo *c;
};
} type_t;
From syntax point of view, the inner union {} can be removed and having *a, *b and *c directly inside the outer union {}. So what's the purpose the namelessly embedded union?
Unnamed union/struct inside another union/struct is a feature of C11, and some compiler extensions (e.g, GCC).
C11 §6.7.2.1 Structure and union specifiers
13 An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.
The advantage of this feature is that one can access its unnamed union field easier:
type_t x;
To access the field a, you can simply use x.a. Compare with the code without using this feature:
typedef union {
int int32;
int boolean;
time_t date;
char *string;
union u{ //difference in here
struct foo *a;
struct foo *b;
struct foo *c;
};
} type_t;
type_t x;
You need to use x.u.a.
Related: unnamed struct/union in C
I think the intended use-case is more “anonymous union inside a struct”, and the behavior of “anonymous union inside a union” being the same as a “flat” union is just an acceptable compromise for consistency.
Allows the same pointer to be called a, b or c. Maybe there is some legacy code that can't agree on what name to use.

Working with a union of structs in C

Say I have the following types:
typedef struct TYPEA
{
int type;
char[12] id;
} TYPEA;
typedef struct TYPEB
{
int type;
int value;
} TYPEB;
I want to use create a union of these types and 'int', so that I can access the "type" int without needing to know whether TYPEA or TYPEB is stored in the union (the value of int lets me determine which is actually stored there). I can't get the right syntax though.
My union:
typedef union MEMBER
{
int type;
struct TYPEA a;
struct TYPEB b;
} MEMBER;
The union is accessed via:
typedef struct WRAPPER
{
union MEMBER* member;
struct WRAPPER* next;
} WRAPPER;
Questions:
(With 'w' as a pointer to an allocated WRAPPER struct) Accessing using w->member->a.id gives "request for member 'id' in something not a structure or union.
Can I assign a pointer to an already malloc'd TYPEA/B to w->member directly? Or does a union need to be malloced specially?
Thanks.
Use w->member->type.
You need to allocate the union specifically.
One note that may be a point of misunderstanding is that the union holds EITHER the int, or TYPEA, or TYPEB, so in particular you cannot rely on your int type; in the union to tell you which struct the union holds.
Edit to respond to question in comments:
You probably want something like this:
struct TYPEA {
char data[30]; // or whatever
};
struct TYPEB {
double x, y; // or whatever
};
struct some_info {
int type; // set accordingly
union {
struct TYPEA a;
struct TYPEB b;
} data; // access with some_info_object.data.a or some_info_object.data.b
};
You defined the member field as a pointer, so you should use
w->member->type instead of w->member.type.
You should malloc the union type. When you allocate a union, you'll get a structure that has a sizeof equal to the largest element in the union. If you try to copy structures into union pointers, you'll mess up the alignment.
w->member.type should be w->member->type because w->member is a pointer.
I don't know off the top of my head whether C will let you assign a TYPEA* or TYPEB* to a MEMBER* - somehow I doubt it. You can always (MEMBER*) it, but I would consider recomposing the structs to remove the int tag and instead declare one struct that includes the tag and a union of TYPEA and TYPEB. The structs ideally shouldn't need to be concerned with the fact that they're in a union.
You might want to check out the code in my question:
Union of structs with common first member
Essentially, I do what you want but I'm using an inner struct (contained in the example) that's common to the two types. This struct can then be cast to gain access to the common elements of both types.

Resources