45

I want to add code that during compilation checks the size of a structure to make sure that it is a predefined size. For example I want to make sure that the size of this structure is 1024 byte when I am porting this code or when I am adding/removing items from structure during compile time:

#pack(1)
struct mystruct
{
    int item1;
    int item2[100];
    char item3[4];
    char item5;
    char padding[615];
 }

I know how to do this during run time by using a code such as this:

 if(sizeof(mystruct) != 1024)
 { 
     throw exception("Size is not correct");
 }

But it is a waste of processing if I do this during run time. I need to do this during compile time.

How can I do this during compilation?

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
mans
  • 17,104
  • 45
  • 172
  • 321
  • The preprocessor doesn't know anything about C++, it only has a very limited set of tokens that it can operate on. You might get somewhere with a static_assert. – PlasmaHH Oct 16 '13 at 11:15
  • 13
    The `sizeof` part is still done at compile time. For a compile time assertion, `static_assert` would work fine. – chris Oct 16 '13 at 11:15
  • you can find an example [here](http://stackoverflow.com/questions/11526526/how-to-combine-static-assert-with-sizeof-and-stringify) – RonenKr Oct 16 '13 at 11:18
  • This is the kind of thing that should be checked in a Unit Test, not in the program itself. – John Dibling Oct 16 '13 at 12:56

5 Answers5

40

Since C++11, you can check the size during compilation:

static_assert (sizeof(mystruct) == 1024, "Size is not correct");

Pre-c++11 compilers, Boost has a workaround:

BOOST_STATIC_ASSERT_MSG(sizeof(mystruct) == 1024, "Size is not correct");

See the documentation.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 10
    Note: regarding the workaround, a non-Boost solution is simply `char const Array[sizeof(mystruct) == 1024 ? 1 : -1];`. – Matthieu M. Oct 16 '13 at 12:23
  • @MatthieuM. with boost you will probably get a nicer error message (at least something with "static assertion failure" in it, if not your own message). – n. m. could be an AI Oct 16 '13 at 16:19
  • 4
    agreed, but some people have to do without. – Matthieu M. Oct 16 '13 at 16:45
  • 1
    If the compiler supports C++11, Boost uses `static_assert`; if not, it falls back to the template instantiation technique, or possibly uses some compiler-specific trick to improve the error message (it recognizes many compilers and adapts itself for them). – n. m. could be an AI Oct 16 '13 at 21:51
27

If you don't have C++11 or Boost, you could try this:

typedef char assertion_on_mystruct[(   sizeof(mystruct)==1024   )*2-1 ];

If the statement is false, then this typedefs an array type with negative size, and your compiler should give an error message. If true, then the size will be one, a valid size. For example, g++ gives:

template.cpp:10:70: error: size of array ‘assertion_on_mystruct’ is negative

I admit it's not the most useful thing, because it only tells you the line number of the error. But it is the simplest, stand-alone, technique I can think of.

A more general macro is:

#define DUMB_STATIC_ASSERT(test) typedef char assertion_on_mystruct[( !!(test) )*2-1 ]

DUMB_STATIC_ASSERT( sizeof(mystruct)==1024 );
DUMB_STATIC_ASSERT( sizeof(my_other_struct)==23 );
DUMB_STATIC_ASSERT( sizeof(minimum_size_struct) >= 23 );
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • 6
    This will work even if you don't have ++ at all, in plain old C. In C++ the template specialization approach is usually preferred though. – Jan Hudec Oct 16 '13 at 11:36
  • I came across this suggestion while looking for an answer to the same problem. I like that this can go in a header where the BUILD_BUG_ON stuff all needs to go in a function. However, I don't like that it creates unnecessary compiler symbols. Any idea if there's a way around that??? I'm in "plain old C", and updating to C11 is a non-option. – Brian McFarland May 22 '15 at 00:17
  • 1
    Ok, I came up with this: `#define SIZE_CHECK_STRUCT( sname, maxsize ) typedef char sname ## _size_check_struct [ 1 - 2* !!(sizeof(struct sname) > (maxsize)) ]`. Leave out `struct` keyword for a version that works on typedef'ed structures. – Brian McFarland May 22 '15 at 00:31
  • @BrianMcFarland, thanks for the `!!` trick, to force an expression into a boolean. I've edited mine accordingly – Aaron McDaid May 22 '15 at 08:43
  • @BrianMcFarland, after seeing your use of `##`, I became worried that mine would fail if there were multiple succesful asserts, because it would mean multiple definitions of the typedef `assertion_on_mystruct`. But it seems it is not a problem (g++ 4.8.4). I think it works because all the definitions are identical (they're all based on `true`, by definition of being successful). Does the standard allow multiple definitions of a typedef, as long as all are identical types? If so, then I think my current version is reasonably robust. – Aaron McDaid May 22 '15 at 08:55
  • 1
    I'm in C, not C++, but I just tested this and apparently `gcc` won't even issue a warning for multiple identical typedefs unless you specify "-Wpedantic". It's only an error if the types are conflicting. – Brian McFarland May 22 '15 at 19:05
  • Perhaps we could arrange that the line number `__LINE__` is included in the name of the typedef? Or maybe just wrap it inside a `do{ }while(0)`? – Aaron McDaid Apr 25 '16 at 21:17
7

From C++11 you have static_assert which is handled on compilation:

static_assert(sizeof(mystruct) == 1024, "Size is not correct");

If the size is not 1024 bytes, you will get a compilation error.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
4

If you want to check it at compile time you may use template metaprogramming phase.

In standard C++ you have boost's static assert, which is hidden by a macro BOOST_STATIC_ASSERT. You would use it in the following way:

#include <boost/static_assert.hpp>
...
BOOST_STATIC_ASSERT(sizeof(mystruct) == 1024);

The above code will fail to compile if the assertion is not met, with some semi-readable error message.

In C++11 you get simpler functionality with static assertions which introduces a new keyword static_assert.

static_assert(sizeof(mystruct) == 1024,"Size is not correct");

Doing the same thing at preprocessor phase cannot be done but it seems not to be really needed in your case.

CygnusX1
  • 20,968
  • 5
  • 65
  • 109
2

Please note that padding is included in sizeof():

struct A { int i; bool b; };

typedef char assertion_on_A[( ((sizeof(A)))== 8 )*2-1 ];
static_assert(sizeof(A) == 8, "sizeof A");

Both the typedef and the static_assert expect size 8 here.

karsten
  • 639
  • 5
  • 13