2016-10-17 6 views
0

У меня есть структура, и не хотят неявного заполнения.Должен ли я беспокоиться о дополнении в конце структуры C++? Я обещаю, что не буду использовать его в массиве

#include <cstdint> 
struct foo 
{ 
    uint8_t a; 
    uint32_t b; 
}; 
static_assert(sizeof(foo) == 8, ""); 

Включает -Wpadded предупреждения.

> g++ test.cpp -c -Wpadded -std=c++14 
test.cpp:5:12: warning: padding struct to align 'foo::b' [-Wpadded] 
    uint32_t b; 
      ^

> clang++ test.cpp -c -Wpadded -std=c++14 
test.cpp:5:12: warning: padding struct 'foo' with 3 bytes to align 'b' [-Wpadded] 
    uint32_t b; 
     ^
1 warning generated. 

Это здорово, и это то, что я хочу.

Теперь я переключу членов вокруг. В конце концов, мне не нужно дополнять, чтобы создать структуру правильного выравнивания. Я бы предпочел просто уменьшить размер.

#include <cstdint> 
struct foo 
{ 
    uint32_t b; 
    uint8_t a; 
}; 
static_assert(sizeof(foo) == 5, ""); 

> g++ test.cpp -c -Wpadded -std=c++14 
test.cpp:2:8: warning: padding struct size to alignment boundary [-Wpadded] 
struct foo 
     ^
test.cpp:7:1: error: static assertion failed: 
static_assert(sizeof(foo) == 5, ""); 
^ 

> clang++ test.cpp -c -Wpadded -std=c++14 
test.cpp:2:8: warning: padding size of 'foo' with 3 bytes to alignment boundary [-Wpadded] 
struct foo 
    ^
test.cpp:7:1: error: static_assert failed "" 
static_assert(sizeof(foo) == 5, ""); 
^    ~~~~~~~~~~~~~~~~ 
1 warning and 1 error generated. 

Это дает мне предупреждение, что я не хочу.

Как я могу получить предупреждение или ошибку времени компиляции, если добавлено неявное дополнение, но если в конце отсутствует прокладка, чтобы выровнять всю структуру? Мне не интересно использовать его в массиве. Или это рискованная и небрежная вещь? Мне нужны экземпляры структуры, которые нужно выровнять правильно.

Есть ли атрибут или модификатор, который достигнет такого же эффекта?

+0

Вы можете использовать '#pragma pack (1)' или любую другую версию g ++, которая есть ... но это также упакует вашу первую структуру. –

+0

. В чем причина отсутствия нежелательной прокладки? –

+0

@ M.M Использование эквивалента #pragma pack (1) дает ловушки «без привязки к памяти» во время выполнения на моей архитектуре, поэтому я не хочу этого делать. Если бы я мог обойти или исправить это, это тоже было бы замечательно. –

ответ

0

Вы можете сделать это:

static_assert(offsetof(foo, b) == offsetof(foo, a) + sizeof(uint8_t), ""); 

Конечно, вы должны добавить один Assert каждого члена после первого, или изменить выше, чтобы включить все поля, например, если c последнее поле:

static_assert(offsetof(foo, c) == sizeof(uint8_t) + sizeof(uint32_t), ""); 

Теперь вы можете быть удивлены, как сделать это более автоматизированным. Вы можете использовать Boost.Fusion, если вы хотите ... вот вопрос, я спросил и ответил вдоль этих линий:

Boost Fusion: validate adapted struct member ordering at compile time

Вы бы использовать тот же подход: сумма размер всех полей до последнего один, и проверьте, совпадает ли смещение последнего поля.

+0

static_asserts для каждого члена не является масштабируемым, если у вас есть, скажем, 15 членов .. :(Спасибо, Boost Fusion выглядит тяжеловесом, но я проверю его ... –

+0

@ JetskiS-type: Boost Fusion действительно тяжелый, но вы можете использовать его в одном файле .cpp, который просто выполняет 'BOOST_FUSION_ADAPT_STRUCT()' и реализует нужные вам проверки. Тогда остальная часть вашей сборки не будет зависеть от нее. –