5

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

#define COMPILER_ASSERT(EXPR)    switch (0) {case 0: case (EXPR):;}

都好。我想扩展它以在以下情况下使用编译器断言。假设我有一个从 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);

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

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

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

谢谢你的帮助。尼克B

4

3 回答 3

2

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

#define GENERIC_ASSERT(EXPR) \
  ((EXPR) ? (void) 0 : assert((EXPR)), (void) sizeof(char[(EXPR) ? 1 : -1]))

如果EXPR是一个错误值的编译时间常数,这将减少为:

(assert((EXPR)), (void) sizeof(char[-1]))

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

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

((void) 0), (void) 1)

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

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

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

prog.c:5: error: size of array ‘type name’ is negative

在 Clang 中要好一些:

error: array size is negative
  GENERIC_ASSERT(2 + 2 == 5);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~
note: expanded from:
  ((EXPR) ? (void) 0 : assert((EXPR)), (void) sizeof(char[(EXPR) ? 1 : -1]))
                                                          ^~~~~~~~~~~~~~~
于 2012-12-18T14:38:54.340 回答
0

这个怎么样 :

#define MY_FUNCTION(X) \
  do{ \
if (X>=1 && X<=20) {\
COMPILER_ASSERT(X != 0); \
my_function(X);\
}\ // end if block
  // you can use break here too
  else myfunction2(X,__FILE__,__LINE__); \ // this will be the runtime assert
 }while (0);


void myfunction2(int x, const char * file, const int line)
{ 
// print here information
exit(-1);
}
于 2012-12-18T14:41:30.457 回答
0

在 P99 我有这个用于静态断言的宏

# if p99_has_feature(c_static_assert)
#  define static_assert _Static_assert
# else
#  define static_assert(EXPR, DIAGSTR)                            \
extern char const p00_compiletime_assert[                         \
 sizeof((void const*[3*(!!(EXPR)) - 1]){                          \
    &p00_compiletime_assert,                                      \
   "static assertion failed: " P99_STRINGIFY(EXPR) ", " DIAGSTR}) \
]
extern char const p00_compiletime_assert[sizeof(void const*[2])];
# endif
#endif

这样做的好处是您几乎可以在任何地方使用它,至少在 C99 中可以使用声明。(C99 允许混合声明和声明)所以这可以在任何类型的功能块内使用,或者在提供EXPR编译时整数常量的文件范围内使用。

于 2012-12-18T14:46:03.343 回答