c++ 如何将static_assert与sizeof和stringify结合起来?

ippsafx7  于 2023-03-20  发布在  其他
关注(0)|答案(7)|浏览(128)

内存使用在我的应用程序中是非常关键的,因此我有一些特定的Assert,在编译时检查内存大小,如果大小与我们之前认为正确的大小不同,则给予一个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) ")");

但是不能在函数调用中使用字符串化(#)操作符。
我还尝试添加双字符串技巧,如下所示:

#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
有没有办法将static_assert中sizeof的结果字符串化?

h9vpoimq

h9vpoimq1#

我将在函数模板上使用调度来执行检查:

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

调试信息位于反向跟踪的模板参数中。
如果这真的更好,你将不得不决定,这也取决于编译器。它还使你能够隐藏预期的大小与模板Map,以总结为一个最大大小和其他花哨的东西。

1rhkuytd

1rhkuytd2#

根据您的编译器,模板可能有助于:

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"
1tu0hz3e

1tu0hz3e3#

正如您所发现的,问题就在这里(另请参见very similar question):

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

这是不可能的,因为字符串化是由预处理器完成的,并且sizeof是在编译期间计算的。

vaqhlq81

vaqhlq814#

这里的解决方案使编译器输出比较值和静态Assert中的特定消息。

#define CAT2(a, b) a##b
#define CAT1(a, b) CAT2(a, b)
#define UNIQUE_ID CAT1(_uid_, __COUNTER__)
#define static_assert_size(VAL, LOW, UP, MSG)               \
  namespace UNIQUE_ID {                                     \
  template <size_t Val, size_t LowBound, size_t UpBound>    \
  struct static_assert_size_ { \
    static_assert(Val >= LowBound && Val <= UpBound, MSG);  \
  }; [[maybe_unused]] static  static_assert_size_<VAL, LOW, UP> sa;                  \                                                     
  };

因此,我们可以这样检查大小:

static_assert_size(impl_size, sizeof(Impl), sizeof(Impl)+32, "impl_size needs to be changed");

并获取Assert错误时的输出:
静态Assert失败:在示例化'struct uid_0::static_assert_size〈512,112,144〉'时需要更改impl_size:在宏“static_assert_size”的扩展中,“(512〈= 144)”在宏“static_assert_size”的扩展中计算为false

q8l4jmvw

q8l4jmvw5#

如果您可以稍微修改结构体的定义,并且不介意有些难看的地方,那么这里有一个替代的只使用头文件的解决方案。

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;

这里的一个警告是,只有在您示例化了某个类型的情况下才会进行检查--仅仅使用指针不会触发错误,因此肯定不是非常适合所有情况!

vlf7wbxs

vlf7wbxs6#

一个简单实用的解决方案是使用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 "!" )
inb24sb2

inb24sb27#

如果您想将静态Assert放置在函数体之外(与the answer above相反),可以使用以下替代检查器:

#include <cstddef>

#define CONCATENATE_DETAIL(x, y) x##y
#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y)
#define MAKE_UNIQUE(x) CONCATENATE(x, CONCATENATE(_, __COUNTER__))

template <std::size_t RealSize, std::size_t ExpectedSize>
void checkSize() {
  static_assert(RealSize == ExpectedSize, "real size != expected size");
}

#define CHECK_SIZE(type, expected_size) \
  inline void MAKE_UNIQUE(checkSize) () { \
    checkSize<sizeof(type), expected_size>(); \
  }

Example用法:

struct MyStruct { std::byte a[42]; };
CHECK_SIZE( MyStruct, 42 ); // check type

相关问题