-3

I have this code

union u_value {
    int i_value;
    long l_value;
    float f_value;
    double d_value;
    char *cp_value;
    int type;
};

union u_value create_int_value(int value) {
    union u_value val;
    val.i_value = value;
    val.type = INT;

    printf("Inside: %d, %d\n", value, val.i_value);

    return val;
}

The problem is that I can't set values inside union.

For example:

union u_value val = create_int_value(123);
printf("%d\n", val.i_value);

will print 0

What am I doing wrong?

ivknv
  • 305
  • 1
  • 4
  • 14
  • 2
    `type` is itself a member of the union. Setting it overwrites whatever value you set previously. If you are trying to implement a tagged union, you will need a `struct` for that, of which one member is a union and **another separate member** is the type tag. – The Paramagnetic Croissant Oct 29 '14 at 11:39
  • @TheParamagneticCroissant I didn't know that. Thank you! Feel so stupid now – ivknv Oct 29 '14 at 11:41
  • well, you don't have to *know* anything special for this. why would the `type` field be special? it's just another member of the union. It shares storage with all of the other members. You need to **understand** what a union is... – The Paramagnetic Croissant Oct 29 '14 at 11:42

2 Answers2

4

You've specified the type member as part of the union, which of course will cause its memory to collide with the rest of the fields.

To create a "tagged union", you must separate the tag from the union. Something like:

struct u_value {
    int type;
    union {
      int i_value;
      long l_value;
      float f_value;
      double d_value;
      char *cp_value;
    } value;
};

Then you can use:

u_value x;
x.type = INT;
x.value.i_value = 4711;

From C11 you can make the inner union anonymous, which is handy.

Community
  • 1
  • 1
unwind
  • 391,730
  • 64
  • 469
  • 606
  • Most compilers will also allow nifty anonymous structs so you can access `x.i_value` directly :) – Quentin Oct 29 '14 at 11:43
1

Let me guess, INT is defined as 0..? You're setting i_value first to 123, and then setting type which, because it's a union is overwriting i_value.

What you need to do is split the type out from the union

union u_value 
{
    int i_value;
    long l_value;
    float f_value;
    double d_value;
    char *cp_value;
};

struct my_type
{
  union u_value value;
  int type;
};

struct my_type create_int_value(int value) {
    struct my_type val;
    val.value.i_value = value;
    val.type = INT;

    printf("Inside: %d, %d\n", value, val.value.i_value);

    return val;
}

Now the type wont overwrite the value.

Sean
  • 60,939
  • 11
  • 97
  • 136