2016-07-27 1 views
13

У меня проблема с проверкой структуры - во время компиляции - если она хорошо выровнена или содержит пробелы. Проверка может быть выполнена в дополнительном тестовом коде, но я не хочу, чтобы «упакованные» данные были в реальном коде реализации.Проверьте на C++, что структура хорошо выровнена или содержит пробелы

Это пример файл заголовок (MyData.h) с типичным включает охрану:

#ifndef MYDATA_H_ 
#define MYDATA_H_ 

struct uneven 
{ 
    int bla_u32; 
    short bla_u16; 
    char bla_u8; 
    /* <-- this gap will be filled in the unpacked version */ 
}; 

#endif // MYDATA_H 

я нашел одно из возможных решений - см ниже.

Вопросы:

  • Есть элегантный способ проверить, если структура uneven содержит разное количество байт по сравнению с его коллегой распакованной в время компиляции?

  • Возможно ли решение, которое будет работать в C (без использования пространства имен)?

+1

Что вы имеете в виду с проверкой, может быть сделано в дополнительном тестовом коде? Вы хотите иметь контроль над размещением утверждения в своем коде? В противном случае вы можете просто определить функцию (аналогичную предложенной @Dutow) в сочетании с вашей реализацией static assert для каждой новой структуры, которую вы хотите проверить временем компиляции. – jcxz

+0

«проверка может быть выполнена в дополнительном тестовом коде» означает, что проверка (также static assert) может быть выполнена в дополнительных файлах c или cpp, которые не являются частью выпущенной базы кода или фактического продукта (например, с использованием дополнительных флагов компилятора или что-то, что не должно быть частью фактического выпуска) –

ответ

3

Вы можете использовать функцию вместо имен (on ideone):

Это решение также работает в C

Заголовочный файл:

typedef struct 
{ 
    int bla_u32; 
    short bla_u16; 
    char bla_u8; 

    /* <-- this gap will be filled in the unpacked version */ 
} uneven; 

Источник файла:

#include "MyData.h" 

#define StaticAssert(cond, msg) switch(0){case 0:case cond:;} 

void checkSizes() 
{ 
    uneven unpacked_uneven; 
#pragma pack(push, 1) 
    #undef MYDATA_H_ // force re-including "MyData.h" 
    #include "MyData.h" 
#pragma pack(pop) 
    uneven packed_uneven; 
    StaticAssert(sizeof(unpacked_uneven) == sizeof(packed_uneven), "uneven contains gaps"); 
} 

Вы можете разместить свой StaticAssert в функции для компиляции e ошибка времени.

+0

Я адаптировал решение от Dutow в соответствии с моим примером кода - я думаю, что это довольно хак, но я бы пошел с этим общим решением, если бы не предупреждение компилятора -Wpadded (см. [ссылка] (http://stackoverflow.com/a/38613971/2056545)) –

2

Я нашел один (как-то противно и очень сложно) решение задачи, которая работает только с C++, а не С.

#define StaticAssert(cond, msg) switch(0){case 0:case cond:;} 

#pragma pack(push, 1) 
namespace packed 
{ 
#include "MyData.h" 
} 
#pragma pack(pop) 

#undef MYDATA_H_ // force re-including "MyData.h" 
#include "MyData.h" 

void checkSizes() 
{ 
    StaticAssert(sizeof(packed::uneven) == sizeof(uneven), "uneven contains gaps"); 
} 

Этот StaticAssert макрос не выполняется для данного неравномерного данных структуры - как размер упакованной версии - 7 байт, а распакованная (нормальная) версия - 8 байтов. Если в конце структуры добавлен дополнительный char, то тест будет успешным - обе версии имеют 8 байт.

+0

Вы можете избежать пространства имен с помощью вложенной структуры. – Dutow

+0

@Dutow, который не помогает с совместимостью C, потому что структуры не имеют области действия в C – user2079303

+1

Альтернативно, '#define uneven packing_uneven #include" MyData.h "#undef uneven'. – MSalters

4

Специальное решение для компилятора, которое работает как для C, так и для C++: GCC имеет опцию предупреждения -Wpadded, которая выдает предупреждение для каждого определения, которое меняет размер из-за выравнивания.

+0

это замечательно - и намного проще! :) - к сожалению, это спецификация gcc. Вместо -Wpadded непосредственно в Makefile (для предотвращения проверки системы включает в себя) Я хотел бы использовать 'диагностическую push' #pragma GCC ' #pragma НКУ диагностическая ошибка «-Wpadded» ' .... код с структурами '#pragma GCC diagnostic pop' –

Смежные вопросы