Время компиляции в отношении размеров данных

Я хотел бы выполнить проверку времени компиляции размеров типоразмеров в проекте C/С++ и ошибку при непредвиденных несоответствиях. Простой

#if sizeof foo_t != sizeof bar_t

не компилируется - утверждает, что sizeof не является правильной константой времени компиляции.

Требуемый объем платформ - по крайней мере Visual С++ с Win32/64 и GCC на x86/amd64.

EDIT: время компиляции, не обязательно препроцессор. Просто не ошибка времени выполнения.

EDIT2: код предполагает, что wchar_t составляет 2 байта. Я хочу ошибку компиляции, если она случайно скомпилирована с 4-байтовыми wchar's.

Ответ 1

У вас есть два варианта:

a) static_assert в С++ 11

b) BOOST_STATIC_ASSERT повышения

Я предпочел бы первый.

Edit:

Препроцессор на самом деле не является частью языка, так как имя говорит, что он предварительно обрабатывает файл, он не знает языка, поэтому он не знает sizeof.

Вы можете использовать некоторый шаблон для генерации кода времени компиляции, например:

template <typename T, bool x = sizeof(T) == 4>
class X;

template <typename T>
class X<T, true> {
  T v;
  const char* msg() const {
    return "My size is 4";
  }
}

template <typename T>
class X<T, false> {
  T v;
  const char* msg() const {
    return "My size is NOT 4";
  }
}

X<int> a;
X<short> b;

Ответ 2

в С++ 11 вы можете использовать static assert

static_assert(sizeof(foo_t) == sizeof(bar_t), "sizes do not match");

Если это pre С++ 11, вы можете использовать макрос boost static assert

http://www.boost.org/doc/libs/1_48_0/doc/html/boost_staticassert.html

BOOST_STATIC_ASSERT(sizeof(int)==sizeof(unsigned));
BOOST_STATIC_ASSERT_MSG(sizeof(int)==sizeof(unsigned), "sizes do not match");

Ответ 3

Если вы не можете использовать С++ 11 или Boost, вы можете найти это полезным:

template <typename A, typename B>
struct MustBeSameSize {
    int c[sizeof(A)-sizeof(B)];
    int d[sizeof(B)-sizeof(A)];
};
template struct MustBeSameSize<int, int>;

Это будет компилироваться только тогда и только тогда, когда sizeof оба типа идентичны. Если они отличаются друг от друга:

template struct MustBeSameSize<char, int>;

тогда вы получите ошибку типа компиляции, но это не будет очень читаемой ошибкой; может быть что-то вроде (g++ 4.4.3):

error: overflow in array dimension

Это работает, потому что любой современный компилятор должен допускать массивы нулевой длины, но не массивы с отрицательной длиной.

Это работает для меня, и я думаю, что g++ в течение некоторого времени допускал массивы нулевой длины. Но я не уверен, насколько это переносится. C99 допускает гибкие элементы массива (т.е. Неопределенный размер), но я не считаю это актуальным. Короче говоря, если вам нужно что-то портативное, используйте С++ 11 или используйте Boost.

Ответ 4

Вы можете определить макрос утверждения времени компиляции следующим образом:

#define COMPILE_TIME_ASSERT( x ) \
  switch ( x ) \
  { \
  case false: \
    break; \
  case ( x ): \
    break; \
  }

Если выражение ложно, вы получите дубликат ошибки метки ярлыка.

Ответ 5

Обнаружение несоответствия размера набора данных или любые проверки привязки константной переменной не удалось найти через компилятор во время компиляции, так как перед компиляцией действуют предпроцессорные директивы. Поэтому, даже если вы можете обнаружить несоответствие, оно не может быть выбрано как ошибка компилятора. Но assert() и т.д. Могут помочь обнаружить время выполнения.
PS: предыдущий ответ, который я дал, не работает с общими компиляторами x86 (но работал с компиляторами ARM).