Friday, 11 March 2011

Anonymous Union / Struct Weirdness

I've been having a look at clang++ / llvm as this will be the new default compiler for Mac, when I came across the following error in some of my code.


In file included from src/Vector.cpp:17:
include/ngl/Vector.h(476) : error: 'm_x' is a protected member of 'ngl::Vector'
return Vector(_k*_v.m_x, _k*_v.m_y, _k*_v.m_z,_v.m_w);
^
include/ngl/Vector.h(423) : note: declared protected here
Real m_x;
^

This is fair enough however this compiled fine with g++, after turning on the pedantic flag in g++ I got the following error

In file included from src/Vector.cpp:17:
include/ngl/Vector.h:437: error: ISO C++ prohibits anonymous structs

Now this is where the plot thickens and I learnt something new.

So clang++ says I have a visibility problem, whereas g++ running normally says this is fine, and g++ in full pedantic mode say no way, who is correct and what is going on?

A Simple Test Class
To test the problems I was encountering I decided to write a simple class as shown below
class Vector
{

public :
Vector(
          const Vector& _v
         ) :
            m_x(_v.m_x),
            m_y(_v.m_y),
            m_z(_v.m_z),
            m_w(_v.m_w){;}

Vector(
         const float& _x=0.0,
         const float& _y=0.0,
         const float& _z=0.0,
         const float& _w=1.0f
         ):
           m_x(_x),
           m_y(_y),
           m_z(_z),
           m_w(_w){;}


private :
  union
  {
    struct
    {
      float m_x;
      float m_y;
      float m_z;
      float m_w;
    };
  float m_openGL[4];
  };

};
So here we have a simple union of 4 floats and an array of 4 floats which if we look at the memory layout would look like this
I then wrote a simple test program which looked like this
int main()
{
 Vector v(1.0,2.0,3.0,1.0);
 v.m_x=2.0;
 std::cout<< v.m_x<<"\n";
}

You will notice in the above program, that I access the member m_x directly. However in the class this is declared in the private section. How does this work?

Well i'm not really sure, according to clang++ "anonymous structs are a GNU extension" so are allowed, however this doesn't account for the breaking of encapsulation.

After further tests I moved the union into the protected area and still it works and I can access the member directly. So it would appear that anonymous struct / unions are always public.

Testing this with Visual Studio 2005 I get the same results, however with the new version of clang++ that ships with Xcode 4 (Apple clang version 2.0 (tags/Apple/clang-137) (based on LLVM 2.9svn)) I get the following



clang++ -pedantic -fdiagnostics-fixit-info VecTest.cpp -o Test
VecTest.cpp:30:5: warning: anonymous structs are a GNU extension [-Wgnu]
    struct
    ^
VecTest.cpp:46:4: error: 'm_x' is a protected member of 'Vector'
        v.m_x=2.0;
          ^
VecTest.cpp:32:13: note: declared protected here
      float m_x;
            ^
VecTest.cpp:47:15: error: 'm_x' is a protected member of 'Vector'
        std::cout<<v.m_x<<"\n";
                     ^
VecTest.cpp:32:13: note: declared protected here
      float m_x;
            ^
1 warning and 2 errors generated.

So it seems clang++ deals with the visibility / scope correctly unlike the other two compilers, for now I think I'm going to move the structs in my library to public anyway as this will give me more speed / access for the basic math classes.

No comments:

Post a Comment