コンパイル中に構造体のサイズをチェックして、定義済みのサイズであることを確認するコードを追加したい。たとえば、このコードを移植するとき、またはコンパイル時に構造に項目を追加/削除するときに、この構造のサイズが1024バイトであることを確認したい:
#pack(1)
struct mystruct
{
int item1;
int item2[100];
char item3[4];
char item5;
char padding[615];
}
次のようなコードを使用して、実行時にこれを行う方法を知っています:
if(sizeof(mystruct) != 1024)
{
throw exception("Size is not correct");
}
しかし、実行時にこれを行うと、処理の無駄です。コンパイル時にこれを行う必要があります。
コンパイル中にこれを行うにはどうすればよいですか?
コンパイル中にサイズを確認できます。
static_assert (sizeof(mystruct) == 1024, "Size is not correct");
そのためにはC++ 11が必要です。 Boostには、c ++ 11以前のコンパイラの回避策があります。
BOOST_STATIC_ASSERT_MSG(sizeof(mystruct) == 1024, "Size is not correct");
ドキュメント を参照してください。
C++ 11またはBoostがない場合、これを試すことができます:
typedef char assertion_on_mystruct[( sizeof(mystruct)==1024 )*2-1 ];
ステートメントがfalseの場合、このtypedefsは負のサイズの配列型であり、コンパイラーはエラーメッセージを表示する必要があります。 trueの場合、サイズは1、有効なサイズになります。たとえば、g ++は以下を提供します。
template.cpp:10:70: error: size of array ‘assertion_on_mystruct’ is negative
エラーの行番号のみを伝えるため、これは最も有用なものではないことを認めます。しかし、それは私が考えることができる最も単純なスタンドアロンの手法です。
より一般的なマクロは次のとおりです。
#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 );
C++ 11では、コンパイル時に処理される static_assert
があります。
static_assert(sizeof(mystruct) == 1024, "Size is not correct");
サイズが1024
バイトでない場合、コンパイルエラーが発生します。
compile timeで確認したい場合は、テンプレートメタプログラミングフェーズを使用できます。
標準C++では、ブーストの static assert があり、マクロBOOST_STATIC_ASSERT
によって隠されています。次の方法で使用します。
#include <boost/static_assert.hpp>
...
BOOST_STATIC_ASSERT(sizeof(mystruct) == 1024);
アサーションが満たされない場合、上記のコードはコンパイルに失敗し、いくつかの読み取り可能なエラーメッセージが表示されます。
C++ 11では、新しいキーワードstatic_assert
を導入する 静的アサーション を使用して、よりシンプルな機能を取得できます。
static_assert(sizeof(mystruct) == 1024,"Size is not correct");
preprocessorフェーズで同じことを行うことはできませんが、実際には必要ないようです。
パディングはsizeof()に含まれていることに注意してください:
struct A { int i; bool b; };
typedef char assertion_on_A[( ((sizeof(A)))== 8 )*2-1 ];
static_assert(sizeof(A) == 8, "sizeof A");
ここでは、typedefとstatic_assertの両方でサイズ8を想定しています。