编译时检查以确保结构中的任何地方都没有填充

Kal*_*cic 3 c++ struct padding static-assert

有没有一种方法可以编写一个编译时断言来检查某种类型是否有填充?

例如:

struct This_Should_Succeed
{
    int a;
    int b;
    int c;
};

struct This_Should_Fail
{
    int a;
    char b;
    // because there are 3 bytes of padding here
    int c;
};
Run Code Online (Sandbox Code Playgroud)

Ker*_*g73 6

从C ++ 17开始,您可能可以使用std::has_unique_object_representations

#include <type_traits>

static_assert(std::has_unique_object_representations_v<This_Should_Succeed>); // succeeds
static_assert(std::has_unique_object_representations_v<This_Should_Fail>); // fails
Run Code Online (Sandbox Code Playgroud)

虽然,这可能无法完全满足您的要求。检查链接的cppreference页面以获取详细信息。

  • 但请注意,对于包含浮点的所有结构(在 IEEE-754 兼容系统上),无论它们是否包含填充,这都会失败。 (3认同)

eer*_*ika 5

编辑:检查Kerndog73的答案

有没有一种方法可以编写一个编译时断言来检查某种类型是否有填充?

是。

您可以将所有成员的sizeof相加,然后将其与类本身的大小进行比较:

static_assert(sizeof(This_Should_Succeed) == sizeof(This_Should_Succeed::a)
                                           + sizeof(This_Should_Succeed::b)
                                           + sizeof(This_Should_Succeed::c));

static_assert(sizeof(This_Should_Fail)    != sizeof(This_Should_Fail::a)
                                           + sizeof(This_Should_Fail::b)
                                           + sizeof(This_Should_Fail::c));
Run Code Online (Sandbox Code Playgroud)

不幸的是,这需要显式命名成员的总和。自动解决方案需要(编译时)反射。不幸的是,C ++语言还没有这种功能。如果幸运的话,也许在C ++ 23中。目前,有一些基于将类定义包装在宏中的解决方案。

不可移植的解决方案可能是使用-WpaddedGCC提供的选项,该选项承诺会在结构包含任何填充的情况下发出警告。可以结合使用#pragma GCC diagnostic push它,仅对选定的结构执行此操作。


我正在检查的类型,类型是模板输入。

一种可移植但不完全令人满意的方法可能是使用模板用户可以使用的自定义特征来自愿保证该类型不包含填充,从而使您能够利用这些知识。

用户将不得不依赖基于明确或基于预处理器的断言,即他们的诺言成立。

  • 这其实也还不够。如果任何成员本身就是结构,我还必须枚举它们的成员等...我有自己的预处理器,因此我可以通过生成该代码进行这样的检查,我只是想知道是否有任何方法可以做到这一点普通 C++。谢谢,这似乎是目前最好的事情! (2认同)