1. ホーム
  2. c

noreturn "関数はなぜ戻るのですか?

2023-10-05 09:33:26

質問

私が読んだのは これ についての質問 noreturn 属性についてです。これは呼び出し元に戻らない関数に使用されます。

では、C言語でプログラムを作ってみました。

#include <stdio.h>
#include <stdnoreturn.h>

noreturn void func()
{
        printf("noreturn func\n");
}

int main()
{
        func();
}

そして、このコードのアセンブリは この :

.LC0:
        .string "func"
func:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $.LC0, %edi
        call    puts
        nop
        popq    %rbp
        ret   // ==> Here function return value.
main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $0, %eax
        call    func

なぜ関数 func() を提供した後に noreturn の属性は?

どのように解決するのですか?

C言語の関数指定子は ヒント であり、どの程度受け入れるかは実装で決まります。

まず最初に _Noreturn 関数指定子(または noreturn を使って <stdnoreturn.h> ) は、コンパイラに 理論的な約束 をコンパイラに伝えるためのヒントです。この約束に基づいて、コンパイラは特定の判断を下し、コード生成のためにいくつかの最適化を行うことができます。

IIRCでは、もし関数が noreturn 関数指定子で指定された関数が最終的に呼び出し元に戻る場合、どちらか一方は

  • を使い、明示的に return ステートメント
  • 関数本体の末尾に到達することで

その の動作は未定義です。 . あなたは はしてはいけません。 は関数から返してはいけません。

明確にするために noreturn 関数指定子 は停止しません。 関数が呼び出し元に戻ることを止めません。これはプログラマがコンパイラに約束したもので、最適化されたコードを生成するために、コンパイラにある程度の自由度を与えるためのものです。

さて、先に約束をした後で、これに違反することを選択した場合、その結果は UB です。コンパイラは、警告を生成することが推奨されていますが、必須ではありません。 _Noreturn 関数が呼び出し元に戻ることが可能であるように見える場合、コンパイラは警告を出すことが推奨されています。

章§6.7.4によると C11 , パラグラフ 8

で宣言された関数は _Noreturn 関数指定子で宣言された関数は、その呼び出し元に戻ってはいけません。

と、12段落目の、( コメントに注意! )

EXAMPLE 2
_Noreturn void f () {
abort(); // ok
}
_Noreturn void g (int i) { // causes undefined behavior if i <= 0
if (i > 0) abort();
}


について C++ については、動作は非常に似ています。章§7.6.4から引用します。 C++14 を、段落2( 強調 )

もし、関数 f が呼び出された場合 f は以前は noreturn 属性と f が最終的に が返された場合、その動作は未定義です。 [ 注意: この関数は例外を投げて終了することがあります。-終了 note ]です。

[注意:実装では、もし [[noreturn]] を返すかもしれない場合、警告を出すことが推奨されます。 を返します。-注意の終わり ]。

3 [ 例

[[ noreturn ]] void f() {
throw "error"; // OK
}
[[ noreturn ]] void q(int i) { // behavior is undefined if called with an argument <= 0
if (i > 0)
throw "positive";
}

-終了例 ]。