检测struct是否有填充

时间:2015-08-14 09:50:02

标签: c++ visual-c++ padding typetraits

如果struct / class有一些填充,是否有一种方法(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 ++不允许(据我所知)生成这种非侵入性(不触及现有结构)

理想情况下,我希望得到像这样的工作

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{};

编辑 - 我为什么需要这个?

我正在使用现有的序列化系统,它存储一些结构只需要void*给它们(在泛型函数内)并存储sizeof(T)个字节数......这样的二进制文件不是由于使用了不同的编译器,因此在我们所针对的平台上可移植,因此无法保证如何插入填充。如果我可以静态检测所有带有填充的结构T,我可以强制用户手动插入填充(一些控制填充,例如不仅仅是随机垃圾),因此没有&#34;随机&#34;填充。另一个优点是,当我对同一个scenerio的两个保存文件进行差异化时,它们看起来是一样的。

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

3 个答案:

答案 0 :(得分:2)

您是否在运行时需要此信息? 因为如果您想在构建时间内了解它,我相信您可以使用static_assert来获取此信息。

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);

同时从之前的帖子中查看此link,也许会有所帮助。

答案 1 :(得分:0)

试试这个宏:

#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");
}

而且,如果你想在编译时遇到错误,可以使用static_assert。

答案 2 :(得分:-1)

可能你应该尝试这样的事情:

#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;
}

我得到了:

sizeof struct = 8
sizeof items  = 5

我在Ubuntu 14.04上。