2

Simplified example:

typedef union {
    int foo;
    char* bar;
} int_or_str;

void baz() {
    int_or_str* bogus = malloc(sizeof(int_or_str) * 43);
    bogus[42].bar = "test";
    printf("%s\n", bogus[42].bar);
}
  1. Should this work, will the compiler assume all 42 members of bogus are char pointers? (Obviously, I could try this, but emphasis on "should").
  2. Is it even defined what happens when you access an array of unions in such a way?
  3. Suppose, I wanted an array of unions which actually hold differently sized values, is it legal? (I could store a layout separately, and compute the offset, if I was sure how union members are laid out in memory).

If you are wondering about motivation for this question: basically, I'm trying to come up with a solution for a run-time defined struct. My idea was to have an array of unions to represent struct fields, plus some meta-data recording how to access those fields.

wvxvw
  • 8,089
  • 10
  • 32
  • 61
  • 5
    That should really be `int_or_str* bogus = malloc(sizeof(int_or_str) * 43);` – Paul Ogilvie Aug 29 '18 at 08:06
  • 1
    This seems a bit like XY problem. It's unclear what the you mean by 3 and with last paragraph. Please expand on them. Your example "works" in some cases, but I am afraid that you might draw wrong conclusions from that. – user694733 Aug 29 '18 at 08:07
  • you will probably be interested in this question : [How can a mixed data type (int, float, char, etc) be stored in an array?](https://stackoverflow.com/questions/18577404/how-can-a-mixed-data-type-int-float-char-etc-be-stored-in-an-array) – Sander De Dycker Aug 29 '18 at 08:08
  • @PaulOgilvie fixed, I typed the example here, so, sorry for typos. – wvxvw Aug 29 '18 at 08:16
  • @SanderDeDycker yeah, that would work, but it wastes memory on tags, and, in my case, often times I can tell in advance that all union members are going to be of the same time. – wvxvw Aug 29 '18 at 08:19
  • @user694733 Essentially, I'm more curious about how it works rather than having a solution to my problem (I can solve it, but in possibly less efficient way). What I really want to know is: is memory allocated per unions is aligned to some value (eg. of the largest union member), or can it be sized differently based on member's size? – wvxvw Aug 29 '18 at 08:21
  • `int_or_str* bogus = malloc(sizeof(*bogus) * 43);` is better (if you change the type of bogus, the line is still valid). Yes, when allocation an union, the size is the size of the biggest member in the union, no matter what you use after. Your code should work, but be carefull (pointeur are not set to NULL, you can't know if the value in your union is an int or a char since you don't store that data, etc etc). – Tom's Aug 29 '18 at 08:27
  • based on your "what I really want to know" comment, this question is answered here : [sizeof a union in C/C++](https://stackoverflow.com/questions/740577/sizeof-a-union-in-c-c) – Sander De Dycker Aug 29 '18 at 08:41

1 Answers1

2

ad 1: Yes it will work.

ad 2: yes, it is perfectly defined.

ad 3: yes it is legal.

The whole idea of a union is that it can hold different types of elements. The size of the union will be the size of the largest element in the union. On a 64 bit system, that will probably be the size of the char *.

So no, the compiler will not assume that all elements are char pointers. That is why you have to use the dot nottion to tell the compile in your statement which type of element you want to access, and the compiler will generate the access.

But as Tom said, you can't know what type of element is currently stored; there must be an external reason (information) by which you know that. If it is important to know it, you should store the information in the data structure, for example:

typedef struct {
    int whatisthis;
    union {
        int foo;
        char *bar;
    } u;
} int_or_str;

and set it like:

int_or_str example;
example.whatisthis= 1;
example.u.foo= 1;

example.whatisthis= 2;
example.u.bar= "test";

and access like:

if (example.whatisthis==1) printf("%d\n", example.u.foo);
if (example.whatisthis==2) printf("%s\n", example.u.bar);
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41