Detect if struct has padding

喜你入骨 提交于 2019-12-04 19:27:23

问题


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)


回答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.




回答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.




回答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.



来源:https://stackoverflow.com/questions/32007188/detect-if-struct-has-padding

工具导航Map