Подтвердить что ты не робот

Проверьте на С++, что структура хорошо выровнена или содержит пробелы

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

Это пример файла заголовка (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 (без использования пространства имен)?

4b9b3361

Ответ 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 байтов.