Why does named union inside struct overwriting other struct members? - c++

struct TestStruct
{
int a;
int b;
union
{
char c[2];
int d;
};
};
TestStruct instance;
If I do
instance.a = 100;
instance.b = 200;
instance.d = 300;
everything's fine.
But, If I give union a name:
struct TestStruct
{
int a;
int b;
union ZZZ // Note here!!
{
char c[2];
int d;
};
};
TestStruct instance;
And I do same things again:
instance.a = 100;
instance.b = 200;
instance.ZZZ::d = 300;
then
instance.ZZZ::d = 300;
is overwriting instance.a to be 300, why?!
Additionally, I can not see the union members in debugger watch list if it has a name.
I am using Visual Studio 2008.

When you name the union there is no longer a data member in the class corresponding to d so instance.ZZZ::d = 300; doesn't mean anything. (With VS2012 I get "error C2039: 'ZZZ' : is not a member of 'TestStruct'")
To have a member of a union type you'll have to give it a name.
struct TestStruct
{
int a;
int b;
union ZZZ // Note here!!
{
char c[2];
int d;
} z;
};
instance.a = 100;
instance.b = 200;
instance.z.d = 300;
C++ has a special rule for 'anonymous unions', where an unnamed union type of the form union { member-specification }; also creates an unnamed object. The names of the union's members are injected into the enclosing scope and access the unnamed object's members.
That's what you're getting when you don't name the union type inside your class. But as soon as you give the type a name the union no longer matches that special rule and there's no longer an unnamed union member in the class; You then have to add the union data member normally, by naming the member variable.

Related

Can an anonymous union be instantiated in c++?

I have this piece of code:
class test {
private:
union {
double x;
std::vector<double> y;
} amIValid;
};
I wonder if the union instance amIValid is valid?
An unnamed union can be instantiated in C++:
union { int i; double d; } my_thing;
my_thing.i = 3;
// etc.
An anonymous union is an unnamed union that is not instantiated (scroll down). You can access its members directly:
union { int i; double d; };
i = 3;
// etc.
So the answer to the question in the title is that an anonymous union cannot be instantiated because instantiating it means that it is not an anonymous union.

Syntax to initialize an anonymous union

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);
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?
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.)

Namespace scope vs scope inside class

There is this code:
namespace N {
struct B {
void f() {
i;
j;
}
int i;
};
int j;
}
int main() {
return 0;
}
Variable i is found but variable j is not. How does it work that variable in the class can be used before it is declared but the same does not work for namespace? How i is found - compiler parses first all class to find all members then bind it with references from member functions?
Indeed, the bodies of member functions (as well as variable initializers) are processed in a later phase than the class definition. You can check for yourself that the "declare before use" rule is still in full effect for class members, by trying to use members in other member declarations:
struct B
{
char c[sizeof i];
int i;
};
Demonstration: http://ideone.com/v1ksio
struct B2
{
decltype(i) f();
int i;
};
This also affects usage of the class itself which requires a complete type.
struct B
{
static char c[sizeof (B)];
};
Demonstration: http://ideone.com/Z9XOzm
But this is ok, because variable initializers are processed when the construction definitions are, where all members are known and the type is complete:
struct B
{
unsigned r{sizeof s};
unsigned s{sizeof (B)};
};

How to zero-initialize an union?

Consider the following code:
struct T {
int a;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
};
int main() {
T x = T();
}
Since an explicit constructor is called, the above code ends-up zero-initializing all the data members in x.
But I would like to have x zero-initialized even if an explicit is not called. To do that one idea would be to initialize the data members in their declaration, which seems to be okay for T::a. But how can I zero-initialize all the memory occupied by the union by using
the same criteria?
struct T {
int a = 0;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
};
int main() {
T x; // I want x to be zero-initialized
}
You could zeroize using memset:
memset(&x, 0, sizeof(x));
For a union without a user-defined default constructor, value initialization is zero initialization.
However, zero-initialization of a union may not zero all memory, but only the padding and the first member. If the first member isn't the largest, you could be left with non-zero content.
Since you know that s2 is largest, you can make a default constructor that zeros it:
struct T
{
int a;
union {
int s1a;
char s2b[1024];
};
T() : a(), s2b() {}
};
And now
T x;
will be zeroed.
I would suggest to implement a constructor for T:
struct T {
int a;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
T() : a(), s2() {} // <- proper initialisation
};
In this case, I picked the largest member of your union since it's transparent. Otherwise you could explicitly create the union itself.

a point from ISO document: based on Anonymous Unions

Point from ISO C++ Standard: section 9.5, para 4, line 1:
"A union for which objects or pointers are declared is not
an anonymous union."
Example :
struct X {
union {
int i;
double d;
} ;
int f () { return i;}
};
int main() { return 0; }
IAm expecting an error from this example according to the above point
but GCC,SUN compiler CC,EDG,etc are not showing error
iam expecting this error// error : cannot directly access "i"
please ..conform above example program is correct are wrong
This would make the union not anonymous:
struct X {
union {
int i;
double d;
} *p;
int f () { return i;} // !Nyet.
};
Cheers & hth.,
To add to what Alf is saying, the purpose of the anonymous union language in the C++ spec is to allow scoping of the unions members. If you have a named union inside a struct:
struct X {
union {
int i;
double d;
} varname;
};
i is not a member of the struct X. i is a member of varname, which itself is a member of struct X.
However, if the union doesn't have a member variable declared, then i would have to be accessed directly as a member of X. This can only work if the union has no name (no variables are declared with the union definition). Such unions are called "anonymous unions".