Cでの静的アサート


回答:


90

C11標準は_Static_assertキーワードを追加します。

これはgcc-4.6以降に実装されています:

_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */

最初のスロットは、整数定数式である必要があります。2番目のスロットは、長くなる可能性のある定数文字列リテラルです(_Static_assert(0, L"assertion of doom!"))。

これは最近のバージョンのclangでも実装されていることに注意してください。


4
[... gcc、clangによって実装されているようです...] ;-)はC11標準の一部であり、C11をサポートするコンパイラにはそれが含まれていると断言できます_Static_assert
PP

1
これはファイルスコープ(関数の外)で使用できますか?私error: expected declaration specifiers or '...' before 'sizeof'はラインを取得しているのでstatic_assert( sizeof(int) == sizeof(long int), "Error!); (ちなみに私はC ++ではなくCを使用しています)
user10607 2014年

@ user10607これが機能しないことに驚いています。待ってください。エラー文字列の最後に引用符がありません。それを入れて戻ってください。これはgcc-4.9で機能します:_Static_assert( sizeof(int) == sizeof(long int), "Error!");私のマシンでエラーが発生します。
emsr 2014年

Ubuntuにgcc4.8.2があります。欠落している引用はコメントのタイプミスでした(私はそれをコードで持っていました)。これは、いくつかのヘッダーが含まれた後のファイルの最初の行です。コンパイラは私に2つのまったく同じエラーを出します:error: expected declaration specifiers or '...' before 'sizeof'AND error: expected declaration specifiers or '...' before string constant(彼は"Error!"文字列を参照しています)(また:私は-std = c11でコンパイルしています。宣言を関数内に置くとすべてうまくいきます(期待どおりに失敗して成功します))
user10607

2
@ user10607コマンドラインで-std = gnu11も指定する必要がありました。4.8と4.8の間に違いがあることに本当に驚いています。1行だけのソースがあります。また_Static_assert、C ++ ishではなくC標準を使用しましたstatic_assert。static_assertマクロを取得するには、 `#include <assert.h>を実行する必要があります。
emsr 2014年

92

これは、関数スコープと非関数スコープで機能します(ただし、構造体、共用体の内部では機能しません)。

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

STATIC_ASSERT(1,this_should_be_true); 

int main()
{
 STATIC_ASSERT(1,this_should_be_true); 
}
  1. コンパイル時のアサーションが一致しなかった場合、ほとんど理解できるメッセージがGCCによって生成されます。 sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative

  2. マクロを変更して、typedefの一意の名前を生成することができます(つまり__LINE__static_assert_...名前の最後に連結します)。

  3. 三元#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]化合物の代わりに、これも使用できます。これは、さびた古いcc65(6502 cpu用)コンパイラでも機能します。

更新: 完全を期すために、これが__LINE__

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X)    COMPILE_TIME_ASSERT2(X,__LINE__)

COMPILE_TIME_ASSERT(sizeof(long)==8); 
int main()
{
    COMPILE_TIME_ASSERT(sizeof(int)==4); 
}

UPDATE2:GCC固有のコード

GCC 4.3(私は推測する)は「エラー」と「警告」機能属性を導入しました。その属性を持つ関数の呼び出しがデッドコードの除去(または他の手段)によって除去できなかった場合、エラーまたは警告が生成されます。これを使用して、ユーザー定義の障害記述を使用してコンパイル時のアサートを行うことができます。ダミー関数を使用せずに、名前空間スコープでそれらをどのように使用できるかを決定する必要があります。

#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })

// never to be called.    
static void my_constraints()
{
CTC(sizeof(long)==8); 
CTC(sizeof(int)==4); 
}

int main()
{
}

そして、これはそれがどのように見えるかです:

$ gcc-mp-4.5 -m32 sas.c 
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true

1
Visual Studioでは、変数名は言及せず、「負の添え字」とだけ表示されます...
szx 2012

NordicMainframe-回答のオプション3はclangでは機能しません。
エラザール2013

1
最後の(GCC 4.3+固有の)ソリューションについて:これは、オプティマイザーが把握できるすべてのものをチェックできるため、非常に強力ですが、最適化が有効になっていないと失敗します。-Ogただし、これが機能するには、最低限の最適化レベル()で十分な場合が多く、デバッグを妨げることはありません。__OPTIMIZE__(および__GNUC__)が定義されていない場合は、静的アサーションをno-opまたはランタイムアサーションにすることを検討できます。
セーレンLøvborg

LINEバージョンのコードスニペット(更新:完全を期すために、ここに `LINEのバージョンがあります)、コンパイル時に、行(STATIC_ASSERT(X、static_assertion_at_line _ ## L))でエラーが発生します。これは、もう1つ追加することで修正できます。以下のようなレベル:#define COMPILE_TIME_ASSERT4(X、L)static_assert(X、#L); #define COMPILE_TIME_ASSERT3(X、L)COMPILE_TIME_ASSERT3(X、 ""アサーション:## L "");
sundar 2016年

__LINE__はgcc4.1.1のバージョンに似たものを使用しています... 2つの異なるヘッダーが同じ番号の行に1つあると、ときどき煩わしくなります!
MM

10

cl

質問でgccが明示的に言及されていることは知っていますが、完全を期すために、Microsoftコンパイラーの調整を行います。

負のサイズの配列typedefを使用しても、clが適切なエラーを吐き出すように説得することはできません。それはただ言うerror C2118: negative subscript。この点では、ゼロ幅のビットフィールドの方がうまくいきます。これには構造体の型指定が含まれるため、実際には一意の型名を使用する必要があります。__LINE__マスタードをカットしません—COMPILE_TIME_ASSERT()ヘッダーとソースファイルの同じ行にある可能性があり、コンパイルが失敗します。__COUNTER__救助に来ます(そしてそれは4.3以来gccにあります)。

#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg) \
    typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \
        CTASTR(static_assertion_failed_,__COUNTER__)

STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)

アンダーclギブ:

エラーC2149: 'static_assertion_failed_use_another_compiler_luke':名前付きビットフィールドの幅をゼロにすることはできません

Gccはまた、わかりやすいメッセージを提供します。

エラー:ビットフィールドの幅がゼロ 'static_assertion_failed_use_another_compiler_luke'


4

ウィキペディアから:

#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}

COMPILE_TIME_ASSERT( BOOLEAN CONDITION );

15
本当のソースにリンクしたほうがいいでしょう:jaggersoft.com/pubs/CVu11_3.html
Matt Joiner

gcc4.6では機能しません-「ケースラベルは整数定数に縮小されません」と表示されます。ポイントがあります。
リオサン2013

あなたはおそらく今までに両方ともwaaayを進めましたが、私は自分で書くことになりました(私の答えを参照しください)。私はあなたのリンク@MattJoinerを使って私を助けました
ハッシュブラウン2014

気になる場合は、@ Liosanさんにご連絡ください。私はC ++を
調べ

Visual C ++に関しては、バージョン2010からstatic_assertが組み込まれており、c ++モードとcモードの両方で機能します。ただし、c99_Static_assertは組み込まれていません。
ddbug 2016年

3

私は考えないで使用したソリューションを使用することをお勧めしますtypedef

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

typedefキーワードを使用した配列宣言は、コンパイル時に評価されるとは限りません。たとえば、ブロックスコープ内の次のコードはコンパイルされます。

int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);

代わりにこれをお勧めします(C99):

#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]

staticキーワードがあるため、配列はコンパイル時に定義されます。このアサートはCOND、コンパイル時に評価されるものでのみ機能することに注意してください。変数に割り当てられた値など、メモリ内の値に基づく条件では機能しません(つまり、コンパイルが失敗します)。


4
これは機能しますが、メモリ要件も増大します。
sherrellbc

1
エラー: 'static_assertion_INVALID_CHAR_SIZE'が定義されていますが、使用されていません[-Werror = unused-variable]
Alex

2

と一緒にSTATIC_ASSERT()マクロを使用する場合__LINE__、.cファイルのエントリとヘッダーファイルの別のエントリの間で行番号の衝突を回避するには、__INCLUDE_LEVEL__。をインクルードします。

例えば ​​:

/* Trickery to create a unique variable name */
#define BOOST_JOIN( X, Y )      BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y )   BOOST_DO_JOIN2( X, Y )
#define BOOST_DO_JOIN2( X, Y )  X##Y
#define STATIC_ASSERT(x)        typedef char \
        BOOST_JOIN( BOOST_JOIN(level_,__INCLUDE_LEVEL__), \
                    BOOST_JOIN(_assert_on_line_,__LINE__) ) [(x) ? 1 : -1]

1

古典的な方法は、配列を使用することです。

char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];

アサーションがtrueの場合、配列のサイズは1で有効であるため機能しますが、falseの場合、サイズが-1の場合はコンパイルエラーが発生します。

ほとんどのコンパイラは変数の名前を表示し、アサーションに関する最終的なコメントを残すことができるコードの右側の部分を指します。


これをジェネリック#define STATIC_ASSERT()型マクロにまとめ、よりジェネリックな例とを使用したジェネリックな例からのサンプルコンパイラ出力を提供すると、よりSTATIC_ASSERT()多くの賛成票が得られ、この手法がより理にかなっていると思います。
ガブリエルステープルズ

同意しません。コンパイラーは思考マクロを見て、より紛らわしいメッセージを出します。
Paolo.Bolzoni

1

Perlから、具体的にはperl.h3455行目<assert.h>事前に含まれています):

/* STATIC_ASSERT_DECL/STATIC_ASSERT_STMT are like assert(), but for compile
   time invariants. That is, their argument must be a constant expression that
   can be verified by the compiler. This expression can contain anything that's
   known to the compiler, e.g. #define constants, enums, or sizeof (...). If
   the expression evaluates to 0, compilation fails.
   Because they generate no runtime code (i.e.  their use is "free"), they're
   always active, even under non-DEBUGGING builds.
   STATIC_ASSERT_DECL expands to a declaration and is suitable for use at
   file scope (outside of any function).
   STATIC_ASSERT_STMT expands to a statement and is suitable for use inside a
   function.
*/
#if (defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L)) && (!defined(__IBMC__) || __IBMC__ >= 1210)
/* static_assert is a macro defined in <assert.h> in C11 or a compiler
   builtin in C++11.  But IBM XL C V11 does not support _Static_assert, no
   matter what <assert.h> says.
*/
#  define STATIC_ASSERT_DECL(COND) static_assert(COND, #COND)
#else
/* We use a bit-field instead of an array because gcc accepts
   'typedef char x[n]' where n is not a compile-time constant.
   We want to enforce constantness.
*/
#  define STATIC_ASSERT_2(COND, SUFFIX) \
    typedef struct { \
        unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
    } _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#  define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#  define STATIC_ASSERT_DECL(COND)    STATIC_ASSERT_1(COND, __LINE__)
#endif
/* We need this wrapper even in C11 because 'case X: static_assert(...);' is an
   error (static_assert is a declaration, and only statements can have labels).
*/
#define STATIC_ASSERT_STMT(COND)      STMT_START { STATIC_ASSERT_DECL(COND); } STMT_END

static_assertが利用可能な場合(から<assert.h>)、それが使用されます。それ以外の場合、条件がfalseの場合、負のサイズのビットフィールドが宣言され、コンパイルが失敗します。

STMT_START/STMT_ENDは、それぞれdo/while (0)に展開されるマクロです。


1

理由:

  1. _Static_assert() Cのすべてのバージョンに対してgccで定義されるようになりました。
  2. static_assert() C ++ 11以降で定義されています

したがって、次の単純なマクロは次の場所でSTATIC_ASSERT()機能します。

  1. C ++:
    1. C ++ 11(g++ -std=c++11)以降
  2. C:
    1. gcc -std=c90
    2. gcc -std=c99
    3. gcc -std=c11
    4. gcc (標準は指定されていません)

STATIC_ASSERT次のように定義します。

/* For C++: */
#ifdef __cplusplus
    #ifndef _Static_assert
        #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
    #endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")

今それを使用してください:

STATIC_ASSERT(1 > 2); // Output will look like: error: static assertion failed: "(1 > 2) failed" 

例:

gcc 4.8.4を使用してUbuntuでテスト済み:

例1:良好なgcc出力(つまり、STATIC_ASSERT()コードは機能しますが、条件がfalseであり、コンパイル時のアサートが発生します):

$ gcc -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c:In function'main '
static_assert.c:78:38:error:static assertion failed: "(1> 2)failed"
#define STATIC_ASSERT(test_for_true )_Static_assert((test_for_true)、 "(" #test_for_true ")failed")
^
static_assert.c:88:5:注:マクロの展開中 'STATIC_ASSERT'
STATIC_ASSERT(1> 2);
^

例2:良好なg++ -std=c++11出力(つまり、STATIC_ASSERT()コードは機能しますが、条件がfalseであり、コンパイル時のアサートが発生します):

$ g ++ -Wall -std = c ++ 11 -o static_assert static_assert.c && ./static_assert
static_assert.c:関数 'int main()'
static_assert.c:74:32:エラー:静的アサーションに失敗しました:(1> 2)失敗しました
#define _Static_assert static_assert / *static_assertはC ++ 11以降の一部です* /
^
static_assert.c:78:38:注:マクロ '_Static_assert'の展開中
#defineSTATIC_ASSERT(test_for_true)_Static_assert((test_for_true)、 "(" #test_for_true ")failed")
^
static_assert.c:88:5:注:マクロの展開中 'STATIC_ASSERT'
STATIC_ASSERT(1> 2);
^

例3: 失敗したC ++出力(つまり、C ++ 11より前のバージョンのC ++を使用しているため、アサートコードがまったく正しく機能しません):

$ g ++ -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c:88:5:警告:識別子 'static_assert'はC ++ 11のキーワードです[-Wc ++ 0x-compat]
STATIC_ASSERT(1> 2 );
^
static_assert.c:関数 'int main()'
static_assert.c:78:99:エラー: 'static_assert'はこのスコープで宣言されていません
#defineSTATIC_ASSERT(test_for_true)_Static_assert((test_for_true)、 "(" #test_for_true " )失敗しました ")
^
static_assert.c:88:5:注:マクロの展開中 'STATIC_ASSERT'
STATIC_ASSERT(1> 2);
^

ここに完全なテスト結果:

/*
static_assert.c
- test static asserts in C and C++ using gcc compiler

Gabriel Staples
4 Mar. 2019 

To be posted in:
1. /programming/987684/does-gcc-have-a-built-in-compile-time-assert/987756#987756
2. /programming/3385515/static-assert-in-c/7287341#7287341

To compile & run:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert

-------------
TEST RESULTS:
-------------

1. `_Static_assert(false, "1. that was false");` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  NO

2. `static_assert(false, "2. that was false");` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             NO
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    NO
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    NO
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    NO
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES

3. `STATIC_ASSERT(1 > 2);` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES

*/

#include <stdio.h>
#include <stdbool.h>

/* For C++: */
#ifdef __cplusplus
    #ifndef _Static_assert
        #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
    #endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")


int main(void)
{
    printf("Hello World\n");

    /*_Static_assert(false, "1. that was false");*/
    /*static_assert(false, "2. that was false");*/

    STATIC_ASSERT(1 > 2);

    return 0;
}

関連:

  1. static_assertを使用して、マクロに渡される型を確認します[私自身の回答]
    1. https://en.cppreference.com/w/cpp/types/is_same
    2. https://en.cppreference.com/w/cpp/language/decltype
  2. static_assertを使用して、マクロに渡される型を確認します
  3. Cで静的アサートを使用してマクロに渡されるパラメーターのタイプを確認する方法

1
static_assertマクロがあるのに、なぜそんなに複雑なのassert.hですか?
さようなら

@KamiKaze、あなたが私の答えを実際に読んでいないように見えるので、私はあなたの質問に驚いていますか?私の答えの2行目は、「static_assert()はC ++ 11以降で定義されています」と言っています。したがって、static_assert()Cではまったく使用できません。en.cppreference.com / w / cpp / language / static_assertも参照してください。static_assert「(C ++ 11以降)」が存在することを示しています。私の答えの美しさは、GccのC90以降、およびC ++ 11以降だけでなく、C ++ 11以降でも機能することstatic_assert()です。また、私の答えは何が複雑ですか?それはほんの数#define秒です。
ガブリエルステープルズ

static_assertC11以降Cで定義されています。に展開されるマクロです_Static_asserten.cppreference.com/w/c/error/static_assert。さらに、あなたの答え_Static_assertとは対照的に、gccのc99とc90では利用できません(gnu99とgnu90でのみ)。これは規格に準拠しています。基本的に、多くの余分な作業を行います。これは、gnu90およびgnu99でコンパイルした場合にのみメリットがあり、実際のユースケースはわずかに小さくなります。
さようなら

>「_ Static_assertはgccのc99およびc90では使用できません(gnu99およびgnu90でのみ)」。意味がわかります。これはgcc拡張なので、正しいです。>「基本的にあなたはたくさんの余分な仕事をします」。同意しません; 2非常に単純な定義は、決して「多くの」余分な作業ではありません。そうは言っても、私はあなたが今何を意味しているのかわかります。私がやったことは今でも有用であり、ここに提示されている知識と回答の本体に価値を付加していると思うので、それが反対票に値するとは思わない。また、「gcc C90以降」または「g90以降」ではなく「C90以降」と言った私の間違いは、上記のコメントにのみあり、私の答えにはありませんでした。
ガブリエルステープルズ

それは事実上間違っていたので、反対票は正当化されました。あなたが間違ったステートメントを訂正するならば、私は答えをもう一度チェックし、私の反対票を撤回するかもしれません。必要がない場合(つまり、gnu90とgnu99を使用しない場合)にこのようなコードを追加しても、わかりやすくするために有益ではなく、さらに煩雑になります。ユースケースがある場合は、それだけの価値があるかもしれません。しかし、gnu99 / 90とc ++ 11の互換性が必要なユースケースの希少性については疑問に思います。
さようなら

0

本当に基本的でポータブルなものが欲しいが、C ++ 11機能にアクセスできない人のために、私はそれだけを書きました。通常どおりに
使用しSTATIC_ASSERT(必要に応じて同じ関数で2回書き込むことができます)GLOBAL_STATIC_ASSERT、最初のパラメーターとして一意のフレーズを使用して関数の外部で使用します。

#if defined(static_assert)
#   define STATIC_ASSERT static_assert
#   define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
#   define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
#   define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif

GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");

int main(int c, char** v) {
    (void)c; (void)v;
    STATIC_ASSERT(1 > 0, "yo");
    STATIC_ASSERT(1 > 0, "yo");
//    STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
    return 0;
}

説明:
最初に、実際のアサートがあるかどうかをチェックします。実際にアサートがある場合は、それを使用する必要があります。
そうでない場合は、predicateを取得し、それをそれ自体で分割することによって主張します。これは2つのことを行います。
ゼロ、id estの場合、アサーションは失敗し、ゼロ除算エラーが発生します(配列を宣言しようとしているため、算術演算が強制されます)。
ゼロでない場合は、配列サイズをに正規化し1ます。したがって、アサーションが成功した場合、述語が-1(無効)または232442(スペースの大量の浪費、最適化される場合はIDK )と評価されたため、とにかく失敗したくないでしょう。
以下のためにSTATIC_ASSERTそれは中括弧に包まれて、これは変数のスコープブロック、作りますassert、つまり何度でも書くことができます。
またvoidunused variable警告を取り除くための既知の方法であるにキャストします。
の場合GLOBAL_STATIC_ASSERT、コードブロック内にある代わりに、名前空間を生成します。名前空間は関数の外で許可されます。unique識別子は、あなたが複数回、このいずれかを使用する場合は任意の矛盾する定義を停止するために必要とされます。


GCCとVS'12C ++で私のために働いた


2
C.には名前空間がありません
martinkunev

ああ、おっと、質問を読み間違えました。とにかくC ++への答えを探してここに来たようです(私の答えの最後の行を見てください)ので、他の人が同じことをする場合に備えてここに残しておきます
ハッシュブラウン2016年

0

これは、「未使用の削除」オプションが設定されている場合に機能します。1つのグローバル関数を使用してグローバルパラメータをチェックできます。

//
#ifndef __sassert_h__
#define __sassert_h__

#define _cat(x, y) x##y

#define _sassert(exp, ln) \
extern void _cat(ASSERT_WARNING_, ln)(void); \
if(!(exp)) \
{ \
    _cat(ASSERT_WARNING_, ln)(); \
}

#define sassert(exp) _sassert(exp, __LINE__)

#endif //__sassert_h__

//-----------------------------------------
static bool tab_req_set_relay(char *p_packet)
{
    sassert(TXB_TX_PKT_SIZE < 3000000);
    sassert(TXB_TX_PKT_SIZE >= 3000000);
    ...
}

//-----------------------------------------
Building target: ntank_app.elf
Invoking: Cross ARM C Linker
arm-none-eabi-gcc ...
../Sources/host_if/tab_if.c:637: undefined reference to `ASSERT_WARNING_637'
collect2: error: ld returned 1 exit status
make: *** [ntank_app.elf] Error 1
//

1
まったく機能する場合は、実行可能ファイルのソースでのみ機能します。
コーダー2015

0

これはいくつかの古いgccで機能しました。バージョンを忘れてしまい申し訳ありません。

#define _cat(x, y) x##y

#define _sassert(exp, ln)\
extern char _cat(SASSERT_, ln)[1]; \
extern char _cat(SASSERT_, ln)[exp ? 1 : 2]

#define sassert(exp) _sassert((exp), __LINE__)

//
sassert(1 == 2);

//
#148 declaration is incompatible with "char SASSERT_134[1]" (declared at line 134)  main.c  /test/source/controller line 134    C/C++ Problem
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.