C编译器断言:如何在修复表达式的地方动态使用它们?

Nic*_*ckB 5 c compiler-construction assert

我的代码广泛使用这样的编译器断言来在构建时标记错误而不是运行时,并通过在运行时不执行断言来提高性能.

#define COMPILER_ASSERT(EXPR)    switch (0) {case 0: case (EXPR):;}
Run Code Online (Sandbox Code Playgroud)

都好.我想扩展这个以使用编译器断言来实现以下情况.假设我有一个从100个地方调用的宏,其中99个传递一个固定值,其中1个传递一个变量.我如何编写宏以使其成为99个位置的编译器断言和最后一个中的运行时断言.

如果我可以保证MY_FUNCTION()总是以固定值调用,我可以这样编码.

void my_function(int x)
{
  //do something
}

#define MY_FUNCTION(X) \
  COMPILER_ASSERT(X != 0); \
  my_function(X)

//These can all take advantage of a compiler assert.
MY_FUNCTION(1);
MY_FUNCTION(SOME_HASH_DEFINE);
MY_FUNCTION(sizeof(SOME_STRUCTURE));
//This can't (this is a contrived example - actual code is complex).
int some_variable = 1;
MY_FUNCTION(some_variable);
Run Code Online (Sandbox Code Playgroud)

所以,如果我不能保证X是固定的,但想要利用每次调用MY_FUNCTION()的位置,我该怎么编码呢?就像是:

#define MY_FUNCTION(X) \
  if (X is a fixed value) COMPILER_ASSERT(X != 0); \
  else assert(X != 0); \ 
  my_function(X)
Run Code Online (Sandbox Code Playgroud)

将调用MY_FUNCTION()重新编码为仅传递固定值对我来说不是一个选项.是的我可以定义MY_FUNCTION_FIXED_X和MY_FUNCTION_VARIABLE_X,但是这会将所有这些暴露给调用代码.

谢谢你的帮助.NickB

eca*_*mur 2

如果您的 C 编译器支持可变长度数组,您可以编写如下内容:

\n\n
#define GENERIC_ASSERT(EXPR) \\\n  ((EXPR) ? (void) 0 : assert((EXPR)), (void) sizeof(char[(EXPR) ? 1 : -1]))\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果EXPR是一个假值编译时间常数,则这会减少为:

\n\n
(assert((EXPR)), (void) sizeof(char[-1]))\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是一个编译错误(它涉及负长度数组)。

\n\n

如果EXPR是一个真值编译时间常数,我们得到:

\n\n
((void) 0), (void) 1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果使用真值编译时间常量调用,Clang 和 gcc 都能够将断言减少为空。

\n\n

如果EXPR有运行时值,sizeof则调用该表达式将导致运行时错误(例如中止),因此assert首先通过使用逗号运算符对其进行排序。

\n\n

不幸的是,在编译时常量的情况下,gcc 输出的错误消息并不是特别具有启发性:

\n\n
prog.c:5: error: size of array \xe2\x80\x98type name\xe2\x80\x99 is negative\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 Clang 中,情况要好一些:

\n\n
error: array size is negative\n  GENERIC_ASSERT(2 + 2 == 5);\n  ^~~~~~~~~~~~~~~~~~~~~~~~~~\nnote: expanded from:\n  ((EXPR) ? (void) 0 : assert((EXPR)), (void) sizeof(char[(EXPR) ? 1 : -1]))\n                                                          ^~~~~~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n