2017-08-08 12 views
2

をアサート含まは、ここでは、コードは:アサーション失敗をトリガするC++:アセンブリコードが結果

.LC0: 
.string "/tmp/compiler-explorer-compiler11778-61-1sgmkbd.5d1m6g8pvi/example.cpp" 
.LC1: 
    .string "true==false" 
main: 
    push rbp 
    mov rbp, rsp 
    mov ecx, OFFSET FLAT:main::__PRETTY_FUNCTION__ 
    mov edx, 5 
    mov esi, OFFSET FLAT:.LC0 
    mov edi, OFFSET FLAT:.LC1 
    call __assert_fail 
main::__PRETTY_FUNCTION__: 
    .string "int main()" 

ラインA、に反映されている:

#include <cassert> 

int main() { 
    assert(true==false); // A 
    assert(true==true); // B 
} 

ここでアセンブリコード(link)はですアセンブリコードですが、Bはありません。

私の質問は:マクロassert()は実行時アサーションのためのものであり、コンパイラはどのように結果を知ってアセンブリに書き込むことができますか?

コンパイラ:gcc 7.1、最適化-O0(つまり最適化なし)。私はそれが最適化のためだと思ったので、私は意図的にこれをオフに切り替えました(私は?)。

編集:今主張は、()コンパイル時に評価することができ、(static_assertと重複しているようだ)。..

+6

"実行時アサーションのためのもので、コンパイラはどのように結果を知り、それをアセンブリに書き込むことができますか?"あなたが書いたアサーションはコンパイル時定数であり、実行時に変更できない可能性があります。 –

+0

また、アサーションは魔法のように消えるように意図されています。 – user1095108

+0

"A"が常にヒットすることをコンパイラが証明するのはかなり簡単なので、 "B"のコードを書くことには何の意味もありません。 –

答えて

4

あなたはそうと仮定すると、GCCおよびGNU Cライブラリを使用しているように見えますNDEBUGは、assertマクロは、おそらくこのような何かを定義している定義されていません。

# define assert(expr)             \ 
    ((expr)                \ 
    ? __ASSERT_VOID_CAST (0)            \ 
    : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION)) 

(私の/usr/include/assert.hからコピーされた)、これを代入する(A NDそれが依存するすべてのマクロ)*はあなたにさえ-O0

int main() { 

    ((true == false) 
     ? static_cast<void>(0) 
     : __assert_fail("true==false", "assert.cpp", 4, "int main()")); 

    ((true == true) 
     ? static_cast<void>(0) 
     : __assert_fail("true==true", "assert.cpp", 5, "int main()")); 
} 

のようなものを取得し、コンパイラはtrue == trueなくtrue == falseので、それはそれは最初__assert_failを呼び出しますが、それは決して知っていることを確認するのに十分なスマートです秒を呼び出します。その2番目の関数は決して呼び出されないので、文字列"true == true"は必要なく、それを含めて気にしません。

より厳しい条件を設定した場合、必要な条件がわからないため、すべてが含まれているはずです。

EDIT to add:さらに複雑な条件で別の行を追加しても、必ずしもそれを追加するわけではありません。例えば、here私は、実行時に行われる必要があり、チェックを追加するようにコードを変更した:

#include <cassert> 

bool check_collatz_conjecture(); 

int main() { 
    // assert(check_collatz_conjecture()); 
    assert(true==false); 
    assert(true==true); 
    assert(check_collatz_conjecture()); 
} 

コンパイラは最初のアサーションがヒットされることを知っている、と__assert_fail__attribute__((__noreturn__))で宣言されているため、コンパイラは知っているので残りの機能については心配する必要はなく、"check_collatz_conjecture()"文字列は含まれていません。最初の主張をコメントアウトすると、Collat​​zの推測が真であるかどうかは分からないので、"true == false"とそれを含むことになります(これは、現在、数学者は現在行っていません)。

は*私は、ファイル名と行番号のマーカーを削除するにはcat assert.ii | sed '/^#/d'を実行し、読みやすくし、手動"int main()"秒で__PRETTY_FUNCTION__秒を置き換えるものにコードを再フォーマットするために、前処理コードを取得するg++ -E assert.cpp -o assert.iiを実行することによってこれを得ました。コンパイラが何かをやっている理由を混乱させるなら、このような前処理された出力を見てみると役に立ちます。

+0

assert()とstatic_assert()の違いは、コンパイル時に**評価する必要があります** assert()**はコンパイル時に評価される可能性がありますが、 、 右? – user8385554

+1

@ user8385554可能であればコンパイラはコンパイル時に必要なものを評価することができます。これは、ユーザー入力、適切にシードされた乱数などのためにはできませんが、それだけでは十分ではないためです。コンパイル時にそれらを処理することも可能です。 –