23

私のアプリケーションでは、メモリ使用量が非常に重要です。したがって、コンパイル時にメモリサイズをチェックし、サイズが以前に正しいと見なしたものと異なる場合はstatic_assertを与える特定のアサーションがあります。

私はこのようなマクロを定義しました:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "!");

このマクロを使用すると、次のように簡単に記述できます。

CHECKMEM(Book,144);
CHECKMEM(Library,80);

問題は、このstatic_assertがオフになると、新しいサイズを見つけるのが非常に難しい場合があることです(たとえば、非表示のコンパイラオプション "/ d1 reportAllClassLayout"を使用することによって)。実際のサイズを含めることができれば、はるかに便利なので、次の代わりに:

ブックのサイズが正しくありません!

それは表示されます

ブックのサイズが正しくありません!(予想144、サイズは152)

私はこのようなものを書いてみました:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " #sizeof(mytype) ")");

ただし、関数呼び出しでstringize(#)演算子を使用することはできません。

また、次のように、二重文字列化のトリックを追加してみました。

#define STR1(x) #x 
#define STR2(x) STR1(x) 
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " STR2(sizeof(mytype)) ")");

ただし、印刷する代わりに、を印刷size is 152しますsize is sizeof(Book)

static_assertでsizeofの結果を文字列化する方法はありますか?

4

5 に答える 5

26

関数テンプレートでディスパッチを使用してチェックを行います。

#include <cstddef>

template <typename ToCheck, std::size_t ExpectedSize, std::size_t RealSize = sizeof(ToCheck)>
void check_size() {
  static_assert(ExpectedSize == RealSize, "Size is off!");
}

struct foo
{
  char bla[16];
};

int main()
{
  check_size<foo, 8>();
  return 0;
}

結果:

In instantiation of ‘void check_size() [with ToCheck = foo; long unsigned int ExpectedSize = 8ul; long unsigned int RealSize = 16ul]’:
bla.cpp:15:22:   required from here
bla.cpp:5:1: error: static assertion failed: Size is off!

デバッグ情報は、バックトレースのテンプレートパラメータにあります。

これが本当に優れている場合は、決定する必要があり、コンパイラにも依存します。また、テンプレートマップを使用して予想サイズを非表示にしたり、最大サイズやその他の凝ったものを合計したりすることもできます。

于 2012-07-17T16:49:32.553 に答える
5

コンパイラによっては、テンプレートが役立つ場合があります。

template<int s, int t> struct check_size {
  static_assert(s == t, "wrong size");
};
check_size<2+2, 5> doubleplusungood;

gcc出力:

prog.cpp: In instantiation of 'check_size<4, 5>':
prog.cpp:5:20:   instantiated from here
prog.cpp:2:3: error: static assertion failed: "wrong size"
于 2012-07-17T16:21:56.890 に答える
2

あなたが発見したように、問題はここにあります(これも非常によく似た質問を参照してください):

#define CHECKMEM(mytype, size)  #sizeof(mytype)

文字列化はプリプロセッサによって行われ、sizeofはコンパイル中に評価されるため、これを行うことはできません。

于 2012-07-17T16:35:41.600 に答える
0

構造体の定義を少し変更でき、醜さを気にしない場合は、ヘッダーのみの代替ソリューションを次に示します。

template <int RealSize = 0, int ExpectedSize = 0>
struct _MyStruct {
    static_assert(RealSize == ExpectedSize, "size is invalid");

    int x;
};

typedef _MyStruct<sizeof(_MyStruct<>), 4> MyStruct;

clang出力:

prog.cpp:4:5: error: static_assert failed "size is invalid"
    static_assert(RealSize == ExpectedSize, "size is invalid");
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~
prog.cpp:12:14: note: in instantiation of template class '_MyStruct<4, 8>' requested here
    MyStruct m;

ここでの1つの注意点は、どこかで型をインスタンス化した場合にのみチェックが行われることです。ポインターを使用するだけではエラーがトリガーされないため、すべての状況に完全に適合するわけではありません。

于 2019-12-31T20:02:12.243 に答える
0

簡単で実用的な解決策は、2- static_assertsを使用することです。

#define CHECKMEM(mytype, size) \
static_assert( sizeof(mytype) <= (size), "Size of " #mytype " is greater than " #size "!" ); \
static_assert( sizeof(mytype) >= (size), "Size of " #mytype " is less than "    #size "!" )
于 2021-01-26T20:45:28.640 に答える