新しい回答 :
私の元の回答 (以下) では、関数スコープとグローバル スコープでアサーションをサポートするために、2 つの異なるマクロが必要でした。両方の範囲で機能する単一のソリューションを考え出すことが可能かどうか疑問に思いました.
extern 文字配列を使用して、Visual Studio および Comeau コンパイラで機能するソリューションを見つけることができました。しかし、GCC で機能するより複雑なソリューションを見つけることができました。しかし、GCC のソリューションは Visual Studio では機能しません。 :(しかし、「#ifdef __ GNUC __」を追加すると、特定のコンパイラに適した一連のマクロを簡単に選択できます.
解決策:
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
(!!sizeof \ (struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
STATIC_ASSERT(1==1, test_message);
で報告されたエラー メッセージは次のとおりです。 test.c の 22 行目:
GCC:
line 22: error: negative width in bit-field `STATIC_ASSERTION__test_message'
ビジュアル スタジオ:
test.c(22) : error C2369: 'STATIC_ASSERTION__test_message' : redefinition; different subscripts
test.c(22) : see declaration of 'STATIC_ASSERTION__test_message'
コモー:
line 22: error: declaration is incompatible with
"char STATIC_ASSERTION__test_message[1]" (declared at line 22)
元の回答 :
私は Checkers がすることと非常によく似たことをします。ただし、多くのコンパイラで表示されるメッセージを含めます:
#define STATIC_ASSERT(expr, msg) \
{ \
char STATIC_ASSERTION__##msg[(expr)?1:-1]; \
(void)STATIC_ASSERTION__##msg[0]; \
}
そして、グローバル スコープ (関数の外) で何かを行うには、これを使用します:
#define GLOBAL_STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
C の静的アサートのさまざまなオプションを調べた Ralf Holly による記事があります。
彼は 3 つの異なるアプローチを提示します:
- 大文字と小文字を切り替える値は一意である必要があります
- 配列は負の次元であってはなりません
- 定数式のゼロ除算
最適な実装に関する彼の結論は次のとおりです。
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
チェックアウト ブーストの静的アサート