9

gcc のドキュメントには、次の内容が含まれています。

関数がインラインと静的の両方である場合、関数へのすべての呼び出しが呼び出し元に統合され、関数のアドレスが使用されない場合、関数自体のアセンブラー コードが参照されることはありません。この場合、オプション -fkeep-inline-functions を指定しない限り、GCC は実際には関数のアセンブラー コードを出力しません。一部の呼び出しは、さまざまな理由で統合できません (特に、関数の定義に先行する呼び出しは統合できず、定義内の再帰呼び出しも統合できません)。

それは私にはいつもばかげているように思えました -- なぜ現代のコンパイラはそれほど馬鹿げているのでしょうか? 簡単なテストの後、それは真実ではないようです。

テストコード:

static inline int foo();

int bar() {
    return foo();
}

int foo() {
    return 42;
}

Linux での gcc-4.9.2 の結果には、 のコードが含まれていますが、 のコードは含まれてbar()いませんfoo()foo()統合されていることがわかります。

bar:
.LFB0:
    .cfi_startproc
    movl    $42, %eax
    ret
    .cfi_endproc

C++ としてコンパイルすると、名前マングリングを除いて、結果は同じです。

ドキュメントに反して、foo()の呼び出し後に定義されているにもかかわらずbar()foo()は完全に に統合されていbar()ます。

ドキュメントを誤解していますか、それとも間違っていますか? おそらく、より複雑なケースでは正しいでしょうか?

「統合」と「インライン」の間に技術的な違いがあるかどうかはわかりませんが、「統合」はキーワードinlineと区別するために使用されており、関数のインライン化を指しているだけだと思います(したがって、タイトル)。

この質問は C および C++ としてタグ付けされています。これは、gcc ドキュメントのこの部分が「C 言語ファミリー」に関連しており、回答が 2 つの言語で同じであると予想されるためです。

4

1 に答える 1

7

Gcc は、一度に 1 つの関数をコンパイルして最適化していました。関数が解析されるとすぐに、次の関数を解析する前に。IIRC、-funit-at-a-timeコンパイルユニット全体を読み取った後に最適化を延期するオプションを導入し、デフォルトで有効にするためにいくつかのリリースを待ったのは、4.X の時間枠だけです。

呼び出しの後に関数をインライン展開する可能性はおそらく-funit-at-a-time作業の一部として導入され、インラインのドキュメント (定義の前の呼び出しに関する記述は少なくとも 2.95 までさかのぼります) は更新されていません。

于 2015-02-06T13:32:01.043 に答える