简体   繁体   English

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

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

Memory usage is quite critical in my application.内存使用在我的应用程序中非常关键。 Therefore I have specific asserts that check for the memory size at compile time and give a static_assert if the size is different from what we considered correct before.因此,我有特定的断言,可以在编译时检查内存大小,如果大小与我们之前认为正确的大小不同,则给出 static_assert。

I have defined a macro like this:我定义了一个这样的宏:

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

This macro makes it very easy to write this:这个宏使得写这个变得非常容易:

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

The problem is that when this static_assert goes off, it might be quite difficult to find out what the new size should be (eg by using the hidden compiler option "/d1 reportAllClassLayout").问题是,当这个 static_assert 关闭时,可能很难找出新的大小应该是多少(例如,通过使用隐藏的编译器选项“/d1 reportAllClassLayout”)。 It would be much handier if I could include the actual size, so instead of:如果我可以包括实际尺寸会更方便,所以不是:

Size incorrect for Book!书的尺寸不正确!

It would show它会显示

Size incorrect for Book, (expected 144, size is 152)书的尺寸不正确,(预期 144,尺寸为 152)

I tried writing something like this:我试着写这样的东西:

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

But you can't use the stringize (#) operator on a function call.但是您不能在函数调用中使用字符串化 (#) 运算符。

I also tried adding the double-stringize trick, like this:我还尝试添加 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)) ")");

But instead of printing size is 152 it prints size is sizeof(Book) .但不是打印size is 152 ,而是打印size is sizeof(Book)

Is there a way to stringify the result of sizeof in a static_assert?有没有办法在 static_assert 中将 sizeof 的结果字符串化?

I'd use dispatching on a function template to do the checking:我会在函数模板上使用调度来进行检查:

#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;
}

Results in:结果是:

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!

The debugging information is in the template parameters of the back-trace.调试信息在回溯的模板参数中。

If this is truly better, you will have to decide and it also depends on the compiler.如果这真的更好,您将不得不做出决定,这也取决于编译器。 It also enables you to hide the expected size with a template map, to sum up to a max size and other fancy things.它还使您能够使用模板映射隐藏预期大小,以总结最大大小和其他奇特的东西。

Depending on your compiler, templates may be able to help:根据您的编译器,模板可能有助于:

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

gcc outputs:海合会输出:

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"

As you discovered, the problem is here (also see this very similar question ):正如您发现的那样,问题就在这里(另请参阅这个非常相似的问题):

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

It is not possible to do, because the stringification is done by the preprocessor, and sizeof is evaluated during the compilation.这是不可能的,因为字符串化是由预处理器完成的,而 sizeof 是在编译期间计算的。

Here's an alternative header-only solution if you can modify the struct's definition a bit and don't mind some ugliness.如果您可以稍微修改结构的定义并且不介意一些丑陋,那么这是一个仅标头的替代解决方案。

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 outputs:铛输出:

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;

One caveat here is that the check will only occur if you instantiate the type somewhere -- just using a pointer won't trigger the error, so definitely not a great fit for all situations!这里需要注意的是,只有在某处实例化类型时才会进行检查——仅使用指针不会触发错误,因此绝对不是适合所有情况!

A simple practical solution is to use 2 static_assert -s:一个简单实用的解决方案是使用 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