Проверьте на С++, что структура хорошо выровнена или содержит пробелы
У меня проблема с проверкой структуры - во время компиляции - если она хорошо выровнена или содержит пробелы.
Проверка может быть выполнена в дополнительном тестовом коде, но я не хочу, чтобы "упакованные" данные были в реальном коде реализации.
Это пример файла заголовка (MyData.h) с типичными атрибутами include:
#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
Я нашел одно возможное решение - см. ниже.
Вопросы:
-
Есть ли элегантный способ проверить, содержит ли struct uneven
другое количество байтов по сравнению с его распакованным экземпляром во время компиляции?
-
Может быть, даже решение, которое будет работать в C (без использования пространства имен)?
Ответы
Ответ 1
Вы можете использовать функцию вместо пространства имен (на 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
в функцию для ошибки времени компиляции.
Ответ 2
Специальное решение для компилятора, которое работает как для C, так и для С++: GCC имеет опцию предупреждения -Wpadded
, которая выдает предупреждение для каждого определения, которое меняет размер из-за выравнивания.
Ответ 3
Я нашел одно (как-то неприятное и очень сложное) решение проблемы, которое работает только с С++, а не с 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 байтов.