Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syntax to initialize an anonymous union

Tags:

c++

unions

If I declare an anonymous union in a function…

void f(int in) {
    union { int i; float f; };
    // …
}

…does syntax exist to initialize it (other than assigning to i or f in another statement? A quick look at the spec suggests no. The obvious ones don’t compile:

// Nope:
union { int i = in; float f; };
union { int i; float f; } = in;
union { int i; float f; } = {in};
union { int i; float f; }{in};
union { int i; float f; }(in);
like image 440
s4y Avatar asked Oct 12 '25 08:10

s4y


2 Answers

This works (at least in gcc 4.7.2):

union { int i; float f; } x = {1};

Notice that the type (i.e. the union) is anonymous but its instanciation is called x.

What you were trying to achieve (e.g. union { int i; float f; }{in};) doesn't compile but suppose it did. Then you would be creating an unnamed object (a temporary) of an unnamed type. The temporary would be destroyed at the end of the expression and, therefore, this statement would have no effect. So what's the point?

like image 102
Cassio Neri Avatar answered Oct 15 '25 01:10

Cassio Neri


See update below -- I'm not sure whether this is a language restriction or a compiler limitation.

In the absence of designated initializers (added to C in 1999, so far nonexistent in C++ as far as I know), an initializer for a union can only specify a value for the first named member:

union { int i; float f; } obj = { 42 }; // sets obj.i to 42

C, as of the 1999 standard, provides designated initializers that let you initialize any named member you like:

union { int i; float f; } obj = { .f = 1.25 };

Since C++ doesn't have this feature, you're pretty much out of luck unless you happen to want to initialize the first named member.

Of course you can use an assignment:

union { int i; float f; } obj;
obj.f = 1.25;

which I suggest is a perfectly good workaround. You can do what you want; you just can't do it with the syntax you want.

Giving the union type a name wouldn't be particularly helpful in this case, unless you make it visible in a wider scope and write a function that returns a value of the type:

union u { int i; float f; };
u init_f(float f) { u result; result.f = f; return result; }

// later

u obj = init_f(1.25);

UPDATE :

I wasn't aware of the existence of anonymous union in C++ when I wrote the above. C11 permits anonymous unions and structs, but only as members of an enclosing union or struct. C++11 permits an anonymous union object to be defined, as in this example from the standard:

void f() {
  union { int a; const char* p; };
  a = 1;
  p = "Jennifer";
}

g++ 4.7.2 seems not to permit anonymous union objects to be initialized. For example, this:

int main() {
    union {
        int i;
        float f;
    } = { 42 };
}

results in the following errors with g++ -std=c++11:

c.cpp: In function ‘int main()’:
c.cpp:5:5: error: expected ‘;’ after union definition
c.cpp:5:7: error: expected primary-expression before ‘=’ token

I don't see anything in section 9.5 of the C++11 standard that forbids initializers for anonymous unions, which makes me think that this is a limitation of g++, presumably to be corrected in a future release.

Whether this limitation is imposed by the language or by g++, you can work around it either by giving the union a name:

union { int i; float f; } obj = { 42 };

(but then you have to refer to obj.i and obj.f rather than just i and f), or by using an assignment rather than an initializer:

union { int i; float f; };
i = 42;

(I'll clean up this answer once we resolve whether this restriction is imposed by the language or by the compiler.)

like image 36
Keith Thompson Avatar answered Oct 15 '25 00:10

Keith Thompson