user1915016
user1915016

Reputation: 176

Structures inside union

int main()
{
  union {
    struct {
      char c[2];
      char ch[2]; 
    } s;
    struct {
       int i;
       int j; 
    } st;
  } u = { (12, 1), (15, 1) };

  printf("%d %d ", u.st.i, u.st.j);
}

How come the above is printing "257 0"?

What difference is created by using {} instead of ()?

Upvotes: 14

Views: 3984

Answers (4)

Potatoswatter
Potatoswatter

Reputation: 137930

{} signifies initializing a sub-object.

() is an operator that groups an expression, e.g. (1+3)*2. You have confusingly used the comma operator, which discards its left-hand operand and returns the right-hand operand. (12,1) is the same as 1.

Initializing a union always sets its first member and ignores the others. This is because only one member at a time can store a value.

Initializing an array subobject with a scalar value, as in passing 1 to initialize c[2], automatically jumps into the array. This is called brace elision. The next 1 will initialize the second member of the array.

You assigned 1 to each of the chars in c[2], and then read back the resulting byte string as a little-endian int. The array ch[2] was not explicitly initialized at all; in C++ it would be set to zero but I'm not entirely sure in C.

The initializer { {12, 1}, {15, 1} } doesn't work because, apparently, brace elision interprets the first } to close the entire union.

The initializer {{ {12, 1}, {15, 1} }} would avoid brace elision and set both arrays. { 12, 1, 15, 1 } should do the same.

Note that the conversion between scalar values and byte strings is implementation-defined; in particular it depends on endianness and the size of int.

Upvotes: 14

Omkant
Omkant

Reputation: 9234

what the difference will it create if i use {} instead of ().

If you are using () then , will be Comma operator and the value assigned will the right- most value inside parenthesis.

But in case of {} , is Comma seperator and each individual value are assigned to corresponding members.But in this case it won't compile and throw an error :

extra brace group at end of initializer.

Upvotes: 0

iabdalkader
iabdalkader

Reputation: 17332

It seems you're misunderstanding the point of unions, objects in unions share their memory so you can only initialize one of the objects not both, in other words the underlying memory is the same, and as mentioned in the other answer initializing a union always sets its first member, so if you want to initialize the second member you can use C99 designated initializers:

u = {.st={15, 1} };

And to initialize the arrays in the first struct:

u = { .s={{12, 1}, {15, 1}} };

Or without .s for the first struct:

u = { {{12, 1}, {15, 1}} };

Upvotes: 0

David Duncan
David Duncan

Reputation: 1215

Both (12, 1) and (15, 1) simplify to (oddly enough) 1. This is because, as Omkant said, you're using the comma operator, which executes each expression it divides, but returns the value of the final expression. The Wikipedia entry actually explains this pretty well.

As a result, u.s.c[0] gets filled with the first 1 and u.s.c[1] gets filled with the second 1. Since a union overlays int u.st.i over u.c[2] and u.ch[2] (assuming 8-bit chars and 32-bit ints), and the architecture is little-endian (known from your result), you have a 1 in the lowest byte of u.st.i and a 1 in its second lowest byte, for a value of 256*1 + 1 = 257.

Meanwhile, no values were written to the memory of u.st.j, so the 2nd output is 0.

Upvotes: 3

Related Questions