Poperton
Poperton

Reputation: 2236

What does it mean for a struct to have an union before the ;?

As you can see in the PointHVDIR struct, it ends with a EIGEN_ALIGN16.

#define PCL_ADD_UNION_POINT4D_HVD       \
  union EIGEN_ALIGN16 {                 \
    float data[4];                      \
    struct {                            \
      float h;                          \
      float v;                          \
      float d;                          \
    };                                  \
  };

  struct PointHVDIR
  {
    PCL_ADD_POINT4D_HVD;                    // quad-word HVD
    float    intensity;                 ///< laser intensity reading
    uint16_t ring;                      ///< laser ring number
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW     // ensure proper alignment
  } EIGEN_ALIGN16;

What does it mean?

Upvotes: 0

Views: 1177

Answers (2)

robthebloke
robthebloke

Reputation: 9678

This will be down to data structure alignment. It can be advantageous on some platforms to align a structure data to 16, 32 or 64bytes (so you can perform an aligned SIMD reads/writes). This is where the macros come in. From C++11 and onwards, you are able to use the alignas() operator to do this:

struct alignas(16) Vec4 
{
  float x,y,z,w;
};

However, prior to C++11 you had to use compiler specific extensions to align data types, e.g. with Visual C++:

struct __declspec(align(16)) Vec4 
{
  float x,y,z,w;
};

or with gcc/linux.

struct __attribute__((aligned(16))) Vec4 
{
  float x,y,z,w;
};

To work around that mess, most libraries will end up wrapping the variations in a macro:

#if __cplusplus >= 201103
# define ALIGN(X) alignas(x)
#elif defined(_MSC_VER)
# define ALIGN(X) __declspec(align(16)) 
#else
# define ALIGN(X) __attribute__((aligned(16)))
#endif

Which leads to a structure definition that looks like:

struct ALIGN(16) Vec4 
{
  float x,y,z,w;
};

In the case of the code above, since the outer PointHVDIR structure has been tagged as 16byte aligned, aligning the anonymous union as well is overkill. The code could be made more readable with:

#define PCL_ADD_UNION_POINT4D_HVD       \
  union {                               \
    float data[4];                      \
    struct {                            \
      float h;                          \
      float v;                          \
      float d;                          \
    };                                  \
  };

  struct PointHVDIR
  {
    PCL_ADD_POINT4D_HVD;           
    float    intensity;            
    uint16_t ring;                 
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW //< ensure alignment when calling new
  } EIGEN_ALIGN16; //< ensure alignment within structs, and on the stack. 

Upvotes: 3

N. Shead
N. Shead

Reputation: 3938

This seems to be from the Eigen codebase? Some quick searching found the following.

From https://gitlab.com/libeigen/eigen/blob/master/Eigen/src/Core/util/ConfigureVectorization.h:

/* EIGEN_ALIGN_TO_BOUNDARY(n) forces data to be n-byte aligned. This is used to satisfy SIMD requirements.
 * However, we do that EVEN if vectorization (EIGEN_VECTORIZE) is disabled,
 * so that vectorization doesn't affect binary compatibility.
 *
 * If we made alignment depend on whether or not EIGEN_VECTORIZE is defined, it would be impossible to link
 * vectorized and non-vectorized code.
 * 
 * FIXME: this code can be cleaned up once we switch to proper C++11 only.
 */

// (code defining EIGEN_ALIGN_TO_BOUNDARY and other things here...)

// Shortcuts to EIGEN_ALIGN_TO_BOUNDARY
#define EIGEN_ALIGN8  EIGEN_ALIGN_TO_BOUNDARY(8)
#define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16)
#define EIGEN_ALIGN32 EIGEN_ALIGN_TO_BOUNDARY(32)
#define EIGEN_ALIGN64 EIGEN_ALIGN_TO_BOUNDARY(64)

In essence, it appears to be specifying that struct is aligned on a 16-byte boundary.

The union in your example, then is not a union named EIGEN_ALIGN16. Instead it's a #define of an anonymous 16-byte-aligned union that is then included as a member of the struct.

Upvotes: 2

Related Questions