C++ 检测结构是否有填充

C++ 检测结构是否有填充,c++,visual-c++,padding,typetraits,C++,Visual C++,Padding,Typetraits,如果结构/类有一些填充,是否有一种方法(trait或其他)来检测 我不需要跨平台或标准化解决方案,我需要用于MSVC2013的解决方案 我可以检查一下 namespace A { struct Foo { int a; bool b; }; } #pragma pack(push, 1) namespace B { struct Foo { int a; bool b; }; } #

如果结构/类有一些填充,是否有一种方法(trait或其他)来检测

我不需要跨平台或标准化解决方案,我需要用于MSVC2013的解决方案

我可以检查一下

namespace A
{
    struct Foo
    {
        int a;
        bool b;
    };
}

#pragma pack(push, 1)
namespace B
{
    struct Foo
    {
        int a;
        bool b;
    };
}
#pragma pack(pop)

static const bool has_padding = sizeof(A::Foo) != sizeof(B::Foo);
<>但C++不允许(据我所知)生成这种非侵入性的(不接触现有结构)< /p> 理想情况下,我想开始这样的工作

template <typename T>
struct has_padding_impl
{
    typedef __declspec(align(1)) struct T AllignedT;
};

template <typename T>
struct has_padding : typename std::conditional<sizeof(typename has_padding_impl<T>::AllignedT) == sizeof(T),
                                               std::false_type,
                                               std::true_type>::type{};
模板
结构具有\u padding\u impl
{
类型定义declspec(align(1))结构T AllignedT;
};
模板
结构有_填充:typename std::conditional::type{};
编辑-我为什么需要这个?

我正在使用现有的序列化系统,它存储一些结构,只需将
void*
带到它们(在泛型函数中)并存储
sizeof(T)
字节数。。。这种二进制文件在我们目标平台上是不可移植的,因为使用了不同的编译器,所以不能保证填充是如何插入的。如果我可以静态地检测所有的
T
,它们都是带填充的结构,我可以强制用户手动插入填充(一些控制填充,例如,不只是随机垃圾),这样就没有“随机”填充。另一个优点是,当我区分相同场景的两个保存文件时,它们看起来是一样的

编辑2
我想得越多,就越意识到我需要跨平台的解决方案。我们主要在msvc2013上开发,但我们的应用程序最终在msvc2012和clang中构建。但如果我在msvc2013中检测到并消除了所有编译器生成的填充,就不能保证其他编译器不会插入填充。。。(因此msvc2013检测是不够的)

可能是您应该尝试以下方法:

#include <iostream>
using namespace std;

struct A
{
    int a;
    bool b;
};

int main(int argc, char *argv[])

{
    A foo;

    cout << "sizeof struct = " << sizeof(A) << endl;
    cout << "sizeof items  = " << sizeof(foo.a) + sizeof(foo.b) << endl;
    return 0;
}

我在Ubuntu 14.04上。

在运行时需要这些信息吗? 因为如果您想在构建时了解它,我相信您可以使用它来获取此信息

struct foo
{
    uint64_t x;
    uint8_t y;
};
#define EXPECTED_FOO_SIZE (sizeof(uint64_t) + sizeof(uint8_t))
static_assert(sizeof(foo) == EXPECTED_FOO_SIZE, "Using padding!");
如果在运行时需要它,可以尝试以下操作:

static const bool has_padding = (sizeof(foo) != EXPECTED_FOO_SIZE);
也可以从前面的帖子中查看,也许会有所帮助。

试试这个宏:

#define TO_STR(str) #str
#define DECL_STRUCT_TEST_ALIGNED(structName, test_alignment, body) \
_Pragma(TO_STR(pack(push,test_alignment)))\
struct test_##structName \
body ; \
_Pragma(TO_STR(pack(pop))) \
struct structName \
body; \
static const bool has_padding_##structName = sizeof(test_##structName)!=sizeof(structName);

DECL_STRUCT_TEST_ALIGNED(bar, 1,
{
                         int a;
                         bool b;
                     }
                     )


DECL_STRUCT_TEST_ALIGNED(foo,1,
{
                         int a;
                         int b;
                     })
现在,您可以在运行时测试:

if (has_padding_foo)
{
    printf("foo has padding\n");
} else {
    printf("foo doesn't have padding\n");
}
if (has_padding_bar)
{
    printf("bar has padding\n");
} else {
    printf("bar has no padding\n");
}

对于ofc,如果您想在编译时得到错误,可以使用static_assert。

为什么您认为需要这个?填充的行为很像未命名的成员。由于无法枚举成员,因此无法区分普通成员和充当填充的“未命名成员”。您知道,可以使用“代码生成配置”页面中的“结构成员对齐”选项指定MSVC填充行为,是吗?@JeroenBaert:这只是他试图发现的变异来源之一。如示例代码所示,它也可以按类定义。在许多情况下,您可以使用
std::has_unique_object_表示法
。请看,这不考虑非填充的额外空间(如vPtr),需要手动枚举成员。谢谢,很遗憾我需要通用解决方案,无法手动枚举所有结构的所有结构成员谢谢,很遗憾我需要通用解决方案,不可能通过handLike@relaxx枚举所有struct的所有struct成员,我遇到了相同的问题,如果不单独枚举所有类型,我看不到简单的解决方案。你知道一个更优雅和通用的解决方案吗?我认为应该将它转换为静态常量bool has_padding=(sizeof(foo)!=预期的_foo_SIZE);或者静态常量bool有\u padding=!(sizeof(foo)=预期的foo大小);只有当大小存在差异时(如果等于无填充),才会显示填充。没有对结果或测试进行预处理对于上层实例中的变量来说才是真正有意义的。谢谢,但如果不涉及现有结构,我看不出这将如何工作,我需要
trait
。请看我的问题好吧,你不需要修改它的内容,你不需要更改它的包,但是你需要使用上面的宏声明它。未接触结构。不接触是指不能修改声明结构的文件?是。我不想(也不能)更改代码库中的所有结构,强迫其他人编写这样的结构,请参见示例Then you Cant it's。你不可能用TMP特质做到这一点。
if (has_padding_foo)
{
    printf("foo has padding\n");
} else {
    printf("foo doesn't have padding\n");
}
if (has_padding_bar)
{
    printf("bar has padding\n");
} else {
    printf("bar has no padding\n");
}