簡體   English   中英

如何將 static_assert 與 sizeof 和 stringify 結合起來?

[英]How to combine static_assert with sizeof and stringify?

內存使用在我的應用程序中非常關鍵。 因此,我有特定的斷言,可以在編譯時檢查內存大小,如果大小與我們之前認為正確的大小不同,則給出 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) ")");

但是您不能在函數調用中使用字符串化 (#) 運算符。

我還嘗試添加 double-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 的結果字符串化?

我會在函數模板上使用調度來進行檢查:

#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!

調試信息在回溯的模板參數中。

如果這真的更好,您將不得不做出決定,這也取決於編譯器。 它還使您能夠使用模板映射隱藏預期大小,以總結最大大小和其他奇特的東西。

根據您的編譯器,模板可能有助於:

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

海合會輸出:

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"

正如您發現的那樣,問題就在這里(另請參閱這個非常相似的問題):

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

這是不可能的,因為字符串化是由預處理器完成的,而 sizeof 是在編譯期間計算的。

如果您可以稍微修改結構的定義並且不介意一些丑陋,那么這是一個僅標頭的替代解決方案。

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

    int x;
};

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

鐺輸出:

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;

這里需要注意的是,只有在某處實例化類型時才會進行檢查——僅使用指針不會觸發錯誤,因此絕對不是適合所有情況!

一個簡單實用的解決方案是使用 2 個static_assert -s:

#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 "!" )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM