找到你要的答案

Q:Detect if struct has padding

Q:检测是否有填充结构

Is there a way (trait or so) to detect, if struct/class has some padding?

I don't need cross-platform or standardized solution, I need it for MSVC2013.

I can check it like

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

But C++ doesn't allow (as far as I know) generate this non-invasive (without touching existing structs)

Ideally I would like to get working something like this

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

EDIT - Why do I need this?

I'am working with existing serialization system, which store some struct just taking void* to them (inside generic function) and store sizeof(T) number of bytes... Such binary file is not portable on platforms we are targeting, since different compilers are used, so there is no guarantee how is padding inserted. If I could statically detect all T which are structs with padding, I can force user to manually insert padding (some control padding e.g. not just random garbage) so there is no "random" padding. Another adventage is, when I diff two save files of same scenerio, they will look the same.

edit 2 the more I think about it, the more I realize I need cross-platform solution. We mainly develop on msvc2013 but our application is at final builded in msvc2012 and clang. But if I detected and get rid of all compiler-generated padding in msvc2013, there is no guarantee that other compiler doesn't insert padding... (so msvc2013 detection is not enough)

有没有一种方法(特质等)进行检测,如果结构/类有一些填充物吗?

我不需要跨平台的、标准化的解决方案,我需要它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进行结构与填充,我可以强迫用户手动插入填充(一些控制填料如不只是随机的垃圾)所以没有“随机”填充。另一个优点是,当我比较两保存相同的场景文件,它们看起来都是相同的。

edit 2 the more I think about it, the more I realize I need cross-platform solution. We mainly develop on msvc2013 but our application is at final builded in msvc2012 and clang. But if I detected and get rid of all compiler-generated padding in msvc2013, there is no guarantee that other compiler doesn't insert padding... (so msvc2013 detection is not enough)

answer1: 回答1:

Do you need this information during run time? Because if you want to know it in build time I believe you can use static_assert to get this information.

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

If you need it during run time, you can try something like:

static const bool has_padding = (sizeof(foo) == EXPECTED_FOO_SIZE);

Also check this link from earlier post, maybe it will help.

Do you need this information during run time? Because if you want to know it in build time I believe you can use static_assert to get this information.

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

也检查这个链接从早期的帖子,也许它会帮助。

answer2: 回答2:

Try out this macro :

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

And now, at runtime you can test :

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

And ofc, you can use static_assert if you want to get error at compile time.

尝试这个宏:

#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如果你想编译时错误。

answer3: 回答3:

May be you should try something like this:

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

I got:

sizeof struct = 8
sizeof items  = 5

I am on Ubuntu 14.04.

也许你应该尝试这样的东西:

#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。

c++  visual-c++  padding  typetraits