C でビルド時に式をアサートする方法

新しい回答 :

私の元の回答 (以下) では、関数スコープとグローバル スコープでアサーションをサポートするために、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)

チェックアウト ブーストの静的アサート