14

I would like to perform a compile-time check on datatype sizes in a C/C++ project, and error on unexpected mismatches. Simple

#if sizeof foo_t != sizeof bar_t 

does not compile - claims that sizeof is not a proper compile-time constant.

The desired scope of platforms - at the very least Visual C++ with Win32/64, and GCC on x86/amd64.

EDIT: compile-time, not necessarily preprocessor. Just not a run-time error.

EDIT2: the code assumes that wchar_t is 2 bytes. I want a compilation error if it's accidentally compiled with 4-byte wchar's.

5
  • Compile-time assert? Or preprocessor-time assert? Commented Dec 5, 2011 at 16:27
  • 4
    How is the compiler supposed to know the size of a complex structure at the level of a preprocessor? There are probably some that could manage it if they want, but it seems definitely outside the scope of a #if. Commented Dec 5, 2011 at 16:27
  • 1
    It is better if you tell us why you want this. Because in this form you wouldn't get answer which could solve this. Preprocessor cannot evaluate sizeof. It is just text-replacement thing. Commented Dec 5, 2011 at 16:29
  • If an error is enough, see stackoverflow.com/questions/1980012/… for a solution valid for C and C++, if you want to do more complex handling, I agree with Mark, the pp can't have the needed information excepted in special cases. Commented Dec 5, 2011 at 16:35
  • @AProgrammer: the negative-size array trick sounds the neatest. Make an answer so that I can a +1. Commented Dec 5, 2011 at 16:55

4 Answers 4

10

in C++11 you can use static assert

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

If it is pre C++11 then you can use boost static assert macro

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"); 
Sign up to request clarification or add additional context in comments.

3 Comments

He asked for compile time, besides does the preprocessor even have that information?
@Nawaz So what? It will give an error if the size doesn't match, which is exactly what the question asks.
Nawaz: To be honest it doesn't really matter how it is done, however the less that is done with the preprocessor and the more that is done with standardized language features the better.
5

You have two options:

a) static_assert of C++11

b) BOOST_STATIC_ASSERT of boost

I would prefer the first one.

Edit:

The preprocessor is not really part of the language, as the name says it pre-processes a file, it has no knowledge of the language, so it does not know sizeof.

You could use some template to do some compile time code generation, for example:

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; 

Comments

3

If you can't use C++11 or Boost, then you might find this useful:

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

That will only compile if and only if the sizeof the two types is identical. If they are different like this:

template struct MustBeSameSize<char, int>; 

then you'll get a compile-type error, but it won't be a very readable error; maybe something like (g++ 4.4.3):

error: overflow in array dimension 

This works because any modern compiler should allow zero-length arrays, but not negative-length arrays.

This works for me, and I think G++ has allowed zero-length arrays for some time. But I'm not sure how portable this is. C99 allows flexible array members (i.e. unspecified size), but I don't think that's directly relevant. In short, if you need something portable, use C++11 or use Boost.

4 Comments

You sure about the latter bit? Um, Visual C++ 2010 does not. At least not on function level (i. e. NOT inside a struct).
@SevaAlekseyev, I'm not sure I understand. Are you confirming that VC++2010 does allow zero-length arrays in structs, and also saying that it does not allow them as function parameters?
I'm saying that void f(){char x[0];} yields compile error C2466: "cannot allocate an array of constant size 0".
You could add a "+1" to each array size to make it work with everything larger than a char. (assuming no odd-sized fundamental types larger than a char)
3

You could define a compile time assert macro like this:

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

If the expression is false, you will get a duplicate case label error.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.