4

Say I have a class/struct with a single union in it... something like:

struct Box { union { AS128 intr; struct { AS32 a, b, c, d; }; }; };

What's the proper way to do an initializer list for this kind of data type?

Box iMyBoxA = { 10, 10, 100, 100 };
Box iMyBoxB = ( Box ){ 10, 10, 100, 100 };

The 'A' option above works in many cases, but isn't completely portable... giving the error "no known conversion for argument 1 from 'brace-enclosed initializer list'". And the second doesn't compile with "Cannot omit braces around initialization of subobject..."

I've tried a few other cases and can't seem to get it to compile across multiple platforms.

  • 2
    You have five separate members in your union. You can only use one, but you give four initializers. – chris Aug 23 '13 at 20:12
  • This question is silly, initialize one by may. –  Aug 23 '13 at 20:21
  • Which compiler are you using? Can we use C99 designated initializers? – andy mango Aug 23 '13 at 20:27
  • Please see http://stackoverflow.com/questions/6161008/union-initialisation –  Aug 23 '13 at 20:27
  • Why would a union have four members of the same type? Are `a, b, c, d` supposed to be members of a structure nested in the union? – Keith Thompson Aug 23 '13 at 20:50
  • Whoops! Yeah, sorry... I mis-typed that. The question is updated. –  Aug 23 '13 at 23:26
  • Jonathan's answer below actually covered the case I really meant to ask about... so no worries. Sorry for the confusion though. –  Aug 23 '13 at 23:35

2 Answers2

4

A union holds only one member at a time, so you initialize it with only one value.

You may use Box iMyBoxA = { value }; to initialize the first-listed member of the union or Box iMyBoxA = { .name = value }; to initialize a particular member by name.

Some notes:

Your code is missing a semicolon after the union declaration; it should be:

struct Box { union { AS128 intr; AS32 a, b, c, d; }; };

Since you have a union inside a struct, you ought to use two sets of braces for the initializers:

Box iMyBoxA = { { value } };

The syntax with one set of braces is permitted but may elicit warnings from your compiler.

Designated initializers (member names in initializers) are a C 1999 feature. This question is tagged with C and C++. A C++ compiler might or might not accept a designated initializer. In C, you would also need to declare Box as a type using typedef or change Box iMyBoxA… to struct Box iMyBoxA….

In C, anonymous unions are new in C 2011.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks for the reply... although I actually mis-typed something in my question. Please give another look and see if it makes more sense. Thanks. –  Aug 23 '13 at 23:27
3

The original version of the structure and union definition in the question was:

struct Box { union { AS128 intr; AS32 a, b, c, d; } };

This is a little unusual. Assuming the types AS128 and AS32 are defined, then it is equivalent to:

struct Box1  // Renamed for convenience of testing
{
    union
    {
        AS128 intr;
        AS32  a;
        AS32  b;
        AS32  c;
        AS32  d;
    };
};

That is, it is a union of an AS128 called intr and 4 separate values of type AS32 called a, b, c and d (with the latter 4 all occupying the same space).

Presumably, what you have in mind is:

struct Box2
{
    union
    {
        AS128 intr;
        struct
        {
            AS32  a;
            AS32  b;
            AS32  c;
            AS32  d;
        } s;
    };
};

This uses the anonymous members feature of C11 (listed in the Foreword of ISO/IEC 9899:2011 as a new feature compared to C99). [The question has now been fixed to reflect more or less this notation (using an anonymous structure). Note that you can't directly designate an anonymous union member, so the s above is a good idea, at least. The structure without the s can be used, but I don't think you can initialize the structure unless you can designate it — you can only designate named elements of a union.]

With the first variant (struct Box1), you can initialize the first member (the AS128 intr; member) with no name:

struct Box1 b1 = { { 1234 } };

The outer braces are for the structure; the inner braces are for the (anonymous) union.

Or you can specify which member to initialize using a designated initializer:

struct Box1 b2 = { { .a = 1234 } };

Note that you can't do:

struct Box1 b3 = { { .a = 1234, .b = 2341 } };

The compiler gives a warning (see the example code below).

With the second variant (struct Box2), with the nested structure, you can still use the undesignated initializer or the designated initializers, but this time, you could specify all 4 of the members of the structure:

struct Box2 b4 = { { .s = { .a = 32, .b = 65, .c = 48, .d = 97 } } };

Example code

Using funny types for the AS128 and AS32 type names.

typedef long AS128;
typedef char AS32;

struct Box1
{
    union
    {
        AS128 intr;
        AS32  a;
        AS32  b;
        AS32  c;
        AS32  d;
    };
};

struct Box2
{
    union
    {
        AS128 intr;
        struct
        {
            AS32  a;
            AS32  b;
            AS32  c;
            AS32  d;
        } s;
    };
};

struct Box1 b1a = { { 1234 } };
struct Box1 b1b = { { .intr = 1234 } };
struct Box1 b1c = { { .a = 32 } };
//struct Box1 b1d = { { .b = 29, .c = 31 } }; // Invalid double initialization
//error: initialized field overwritten [-Werror=override-init]

struct Box2 b2a = { { 1234 } };
struct Box2 b2b = { { .intr = 1234 } };
struct Box2 b2c = { { .s = { .a = 29, .b = 30, .c = 31, .d = 32 } } };
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thanks for the detailed reply! And you actually fixed my mis-type already... I meant to ask about your 'Box2' example. Let me give this a shot. –  Aug 23 '13 at 23:28
  • Nice! Your last example is exactly what I wanted. Thanks. :) –  Aug 23 '13 at 23:33
  • Actually... one last question. Is there no way to leave off the name for the internal struct? I'd really prefer something like `struct Box2 b2d = { { 29, 30, 31, 32 } };` so that I don't have to refer to `b2d.a` as `b2d.s.a`. –  Aug 23 '13 at 23:47
  • 1
    The unnamed initializers would work as long as you designate the structure: `struct Box2 b2d = { { .s = { 29, 30, 31, 32 } } };`. Or you could place the structure ahead of `intr` so it was the first member of the union, and then you'd write: `struct Box2a b2d = { { { 29, 30, 31, 32 } } };`. I've not verified this with the compiler, but I believe it is true. – Jonathan Leffler Aug 23 '13 at 23:50
  • 1
    Note my new commentary about naming the structure element in the union so that you can designate it for initialization; I wasn't able to initialize an anonymous element of a union — but I may not have spent enough time working through the compiler error messages. – Jonathan Leffler Aug 23 '13 at 23:55
  • Ah, good point... the order might actually be relevant. I'll give that a try. –  Aug 23 '13 at 23:56
  • Yeah, you got it! Moving the struct to the first member in the union and using the triple-bracket approach seems to be working. Thanks again, that's just what I've been looking for. –  Aug 24 '13 at 00:00