Утверждение времени компиляции на типах данных - PullRequest
12 голосов
/ 05 декабря 2011

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

#if sizeof foo_t != sizeof bar_t

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

Желаемая область применения платформ - по крайней мере, Visual C ++ с Win32 / 64 и GCC на x86 / amd64.

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

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

Ответы [ 5 ]

10 голосов
/ 05 декабря 2011

в C ++ 11 вы можете использовать статический assert

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

Если это предварительно C ++ 11, то вы можете использовать форсированный статический макрос 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");
5 голосов
/ 05 декабря 2011

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

а) static_assert C ++ 11

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

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

Изменить:

Препроцессор на самом деле не является частью языка, так как название говорит, что он предварительно обрабатывает файл, он не знает языка, поэтому он не знает 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;
3 голосов
/ 19 января 2012

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

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

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

3 голосов
/ 06 декабря 2011

Если вы не можете использовать C ++ 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 допускает гибкие члены массива (то есть неопределенный размер), но я не думаю, что это имеет прямое отношение.Короче говоря, если вам нужно что-то переносимое, используйте C ++ 11 или Boost.

0 голосов
/ 05 декабря 2014

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

...