5

私のコードでは、このようなコンパイラ アサートを広範囲に使用して、実行時よりもビルド時にエラーにフラグを立て、実行時にアサートを実行しないことでパフォーマンスを向上させています。

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

すべて良い。これを拡張して、次の場合にコンパイラのアサートを使用したいと思います。100 か所から呼び出されるマクロがあり、そのうち 99 か所が固定値を渡し、そのうちの 1 か所が変数を渡すとします。これを 99 か所でコンパイラ アサートにし、最後の 1 か所でランタイム アサートにするマクロをコーディングするにはどうすればよいでしょうか。

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 はどちらも、真の値のコンパイル時定数で呼び出された場合、アサートをゼロに減らすことができます。

EXPR実行時の値がある場合、式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

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 に答える
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 に答える