Hey all,
I've got a bit of an odd question, that I can't seem to find any infomation about.
What i'm interested in is the behavour of a struct/union constructed like this:
Code:
typedef struct {
uint64_t num1;
uint64_t num2;
} st_a;
typedef struct {
uint64_t num1;
uint32_t num2;
} st_b;
typedef struct {
uint32 type;
union {
st_a a;
st_b b;
} u;
} somestruct;
somestruct* newsomestruct(uint32_t type) {
somestruct* result = NULL;
switch(type) {
case 0:
result = malloc(sizeof(uint32) + sizeof(st_a));
result->type = type;
result->u.a.num1 = 0;
result->u.a.num2 = 0;
case 1:
result = malloc(sizeof(uint32) + sizeof(st_b));
result->type = type;
result->u.b.num1 = 0;
result->u.b.num2 = 0;
}
return result;
}
What kind of behavour could I expect from object, in the following cases:
1. newsomestruct(0)->u.a.num1 = 2;
2. newsomestruct(1)->u.b.num1 = 2;
3. newsomestruct(0)->u.a.num2 = 2;
4. newsomestruct(1)->u.b.num2 = 2;
5. newsomestruct(0)->u.b.num1 = 2;
6. newsomestruct(1)->u.a.num1 = 2;
7. newsomestruct(0)->u.b.num2 = 2;
8. newsomestruct(1)->u.a.num2 = 2;
9.
Code:
somestruct* ss1 = newsomestruct(0);
somestruct* ss2 = newsomestruct(1);
* ss1 = * ss2;
10.
Code:
somestruct* ss1 = newsomestruct(0);
somestruct* ss2 = newsomestruct(1);
* ss2 = * ss1;
This is what I'd expect, but I can't find any evidence online in C standards or elsewhere:
1. Works as expected, sets the value of a.num1 to 2.
2. Works as expected, sets the value of b.num1 to 2.
3. Works as expected, sets the value of a.num2 to 2.
4. Works as expected, sets the value of b.num2 to 2.
5. Works as expected, sets the value of b.num1 to 2.
6. Works as expected, sets the value of a.num1 to 2.
7. Works as expected, sets the value of b.num1 to 2.
8. Crashes/Memory Corruption, attempted to alter memory outside struct.
9. Works as expected, * ss1 == * ss2
10. Crashes/Memory Corruption, attempted to alter memory outside struct.
I've tested simular code on my machine (Xubuntu 14.04LTS compiled with gcc on -O3) and it appears to be reliable, given that you stick with acessing the type tagged in the struct or the common initial union struct members (in this case num1).
This is likely bad practice, since I assume it's undefined behavour, but if the behavour is defined I assume it's about as dangerous as a pointer (AKA don't control how you use it and things go wrong)
Eitherway I'm interested in what's going on behind the scenes and if this could be used, somewhat safely, given that the type tag for the union is respected.
Thanks for your time and sorry if it's a bit rambly / poorly worded (It's a getting a bit late)