在C++中检查结构是否对齐或包含间隙

Check in C++ that a struct is well aligned or contains gaps

本文关键字:对齐 包含 间隙 是否 结构 C++ 检查      更新时间:2023-10-16

我遇到了一个问题,在编译时,如果结构对齐良好或包含间隙,就应该检查它。检查可以在额外的测试代码中完成,但我不希望在真正的实现代码中"打包"数据。

这是一个示例头文件(MyData.h),具有典型的包含保护:

#ifndef MYDATA_H_
#define MYDATA_H_
struct uneven
{
  int bla_u32;
  short bla_u16;
  char bla_u8;
  /* <-- this gap will be filled in the unpacked version */
};
#endif // MYDATA_H

我找到了一个可能的解决方案——见下文。

问题:

  • 有没有一种优雅的方法可以检查结构体uneven与编译时未打包的对应结构体相比是否包含不同数量的字节?

  • 有没有一个解决方案可以在C中工作(不使用名称空间)?

一个同时适用于C和C++的编译器特定解决方案:GCC有一个警告选项-Wpadded,它为每个因对齐而更改大小的定义生成一个警告。

您可以使用函数而不是名称空间(在ideone上):

此解决方案也适用于C

头文件:

typedef struct
{
  int bla_u32;
  short bla_u16;
  char bla_u8;
  /* <-- this gap will be filled in the unpacked version */
}  uneven;

源文件:

#include "MyData.h"
#define StaticAssert(cond, msg) switch(0){case 0:case cond:;}
void checkSizes()
{
  uneven unpacked_uneven;
#pragma pack(push, 1)
  #undef MYDATA_H_ // force re-including "MyData.h"
  #include "MyData.h"
#pragma pack(pop)
  uneven packed_uneven;
  StaticAssert(sizeof(unpacked_uneven) == sizeof(packed_uneven), "uneven contains gaps");
}

您可以将StaticAssert放入函数中以处理编译时错误。

我为这个问题找到了一个(不知何故很讨厌,也很棘手)的解决方案,它只适用于C++,而不适用于C.

#define StaticAssert(cond, msg) switch(0){case 0:case cond:;}
#pragma pack(push, 1)
namespace packed
{
#include "MyData.h"
}
#pragma pack(pop)
#undef MYDATA_H_ // force re-including "MyData.h"
#include "MyData.h"
void checkSizes()
{
  StaticAssert(sizeof(packed::uneven) == sizeof(uneven), "uneven contains gaps");
}

对于给定的不均匀结构数据,此StaticAssert宏将失败,因为打包版本的大小为7字节,而未打包(正常)版本为8字节。如果在结构的末尾添加一个额外的char,则测试成功——那么两个版本都有8个字节。