the below code provided an O/P :
101:name_provided:name_provided
AFAIK a union can hold only one member at a time, but it looks like both values are visible , is that correct or anything wrong with the code.
#include <stdio.h>
struct test1{
char name[15];
};
struct test2{
char name[15];
};
struct data{
int num;
union{
struct test1 test1_struct;
struct test2 test2_struct;
};
};
int main()
{
struct data data_struct={101,"name_provided"};
printf("\n%d:%s:%s",data_struct.num,data_struct.test1_struct.name,data_struct.test2_struct.name);
return 0;
}
A union specifies that both members will be located at the same place in memory. So if you assign to test1_struct and then read from test2_struct, it will interpret the contents of test1_struct as if it were in the format of test2_struct.
In this case, both structures have the same format, so it doesn't make a difference which one you read and write. It generally makes no sense to use a union where both members are equivalent. The usual purpose of a union is to have different types of members, but not need to have separate memory for each of them, because you only need to use one type at a time. See How can a mixed data type (int, float, char, etc) be stored in an array? for a typical use case.
And see Unions and type-punning for the consequences of accessing a different member than the one you assigned to.
Related
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.
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.
union Data
{
int i;
float f;
char str[20];
} data;
structure Data
{
int i;
float f;
char str[20];
} data;
Here, as I know,"data" is a tag and it is optional. What exactly is it? What advantages can I get by adding a tag while declaring a structure or a union.
Here, as I know,"data" is a tag and it is optional.
No, there is no tag here. A tag indicates which interpretation of a union is correct. For example, if your code assigns data.f and passes data to another function and it reads data.str then you'll have a massive failure in your program that is likely to crash it. The union itself doesn't give the function enough information to know which union member to use.
By adding a tag, you can indicate which interpretation is correct. For example:
struct TaggedData
{
int type;
union Data value;
} taggeddata;
Where type is the tag and indicates what kind of value is stored in the union. A function that reads taggeddata can now use a switch statement and access the correct union member.
Another common name for a tagged data structure is a variant type. Compare to Boost.Variant.
I have the following piece of code:
struct sched_param {
union {
int sched_priority;
struct rcost_sched_param rcost_params;
};
};
I want to know which of the two parameters is "active". Is there a way for me to do that other than adding a int to the struct sched_param?
struct sched_param {
int type;
union {
int sched_priority;
struct rcost_sched_param rcost_params;
};
}
you can add member named type,save the data which parameters is "active"
No, that's the tricky part here: You'll have to store the information which union entry to use (e.g. using a single char member). Also note that both union entries might not necessarily point to the same locations (as you might expect, e.g. due to packing or endianess), so you can't just read one value and determine whether it's containing a valid value or not, since it's up to the compiler how to implement the struct in the union behind the scenes.
I just wonder, if I have a function that accept a struct that contain union inside it, how can I know the content of that union:
struct command{
int *input;
int *output;
union{
char **word;
struct command *subcommand;
} u;
};
the function:
void readCommand(command cInput){
if(cInput.u is char) print the content of array of array of char
else readCommand(cInput.u); //make a recursive call
}
any suggestion? thank you
note: I can't change the content of struct command.
You cannot. That's the nature of a union. If you need to, you must embed the union in a struct and put a type indicator in the struct.
You can't; you must assume what the underlying data is or have access to other information which can tell you what the current underlying type is. It is only valid to extract the appropriate underlying type.
If you receive objects of this type from black-box without any information about this object, there is no way to do that without changing struct command structure.
With unions, you always need some kind of a discriminator to indicate which particular object inhabits the union. It can be a enum or some other value which tells you the nature of the object.
For example:
struct command{
int *input;
int *output;
int type; // <-- e.g. this value is the union discriminator; 1 => word, 2 => subcommand
union{
char **word;
struct command *subcommand;
} u;
};