4

inlineこのキーワードは、最新のコンパイラのヒントとしてはもはや役に立たず、マルチソース プロジェクトでの複数定義エラーを回避するために使用されているとよく耳にします。

しかし、今日、コンパイラがキーワードに従う例に遭遇しました。

inlineキーワードなしの場合、次のコード

#include <iostream>

using namespace std;

void func(const int x){
    if(x > 3)    
        cout << "HAHA\n";
    else
        cout << "KKK\n";
}

int main(){
    func(5);
}

コマンドを使用すると、インライン化g++ -O3 -S a.cppされていないアセンブリ コードが生成されます。func

ただし、 の定義の前に inline キーワードを追加するとfuncfuncは にインライン化されmainます。

生成されたアセンブリ コードの一部は、

.LC0:
    .string "HAHA\n"
.LC1:
.string "KKK\n"
.text
.p2align 4,,15
.globl  _Z4funci
.type   _Z4funci, @function
_Z4funci:
.LFB975:
    .cfi_startproc
    cmpl    $3, %edi
    jg  .L6
    movl    $4, %edx
    movl    $.LC1, %esi
    movl    $_ZSt4cout, %edi
    jmp _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    .p2align 4,,10
    .p2align 3

main:
.LFB976:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $5, %edi
    call    _Z4funci
    xorl    %eax, %eax
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc

私のコンパイラは gcc 4.8.1 / x86-64 です。

リンク プロセス中に関数がインライン化される可能性があると思われますが、インライン化されるかどうかはわかりません。

私の質問は、このコード スニペットが 、関数/メソッドのキーワード「インライン」をいつ書くべきかなどの最新のガイドラインと矛盾しているように見える理由です。

4

4 に答える 4

3

inlineキーワードにはいくつかの効果があります。そのうちの 1 つは、関数をインライン化することをコンパイラーに示唆することです。 MS__forceinlineや gccなど__attribute__(always_inline)]。

また、inlineキーワード has を使用すると、関数がインライン化されている場合に、「同じ関数の複数の定義」のエラーを取得することなく、同じ名前の関数の複数のインスタンスを持つことができます。[しかし、関数は毎回同じソースでなければなりません]。

この場合、コンパイラが inline ではないことに少し驚いていますfunc。ただし、に追加staticするfuncと、インラインにもなります。したがって、明らかにコンパイラは、「他の関数も使用している可能性があるfuncため、とにかくコピーが必要であり、それをインライン化してもあまり利益はありません。実際、関数を静的にすると、それは関数が非常に大きい場合でも、gcc/g++ はほぼ確実にインライン化します。

コンパイラに何かをインライン化させたい場合は、追加しても問題はありませんinline。ただし、多くの場合、コンパイラはどちらの方法でも適切な選択を行います。たとえば、コードを次のように変更すると:

const char* func(const int x){
    if(x > 3)    
        return "HAHA\n";
    else
        return "KKK\n";
}

int main(){
    cout << func(5);
}

return "HAHA\n";の左側の部分をインライン化しfuncます。

インライン化するかどうかを決定するコンパイラのロジックは複雑であり、その一部は「どれだけ多くのコード空間を占有するかに対して、どれだけ得られるか」operator<<(ostream& ,const char *)です。この場合のインライナー。残念ながら、コンパイラが特定の決定を下す理由を理解するのは必ずしも容易ではありません...

于 2013-09-21T12:11:51.727 に答える
2

まず、それほど白黒ではありません。このキーワードの唯一の絶対的な効果はinline、ODR ルールを抑制し、複数の定義エラーを回避することです。それを超えて、コンパイラは確かにインライン化に関するヒントとしてキーワードを自由に使用できますが、そうする場合としない場合があります。(そして、私が見てきたことから、実際には、コンパイラは通常、この最適化のヒントを無視します。なぜなら、ほとんどの人はインライン化する頻度や何をインライン化するのか見当がつかず、コンパイラはそれをより適切に処理できるからです)。しかし、ヒントを無視する必要はありません。

第二に、呼び出しがキーワードでインライン化されているが、キーワードなしでインライン化されていない別の理由がある可能性がありますinline

キーワードがないinline場合、関数定義をエクスポートする必要があります。これは、別の TU がそれにリンクする必要がある可能性があるためです。関数定義をエクスポートする必要があるため、コードは既にそこにあり、呼び出しをインライン化することは、関数本体を効果的に複製したことを意味します。より多くの総コード、より大きな実行可能ファイルのサイズ、命令キャッシュのローカリティへのヒット。

しかし、inlineキーワードを使用すると、コンパイラは関数定義をエクスポートする必要がないため、呼び出しをインライン化し、元の定義を完全に削除できます。その後、合計コード サイズは増加しません (関数定義とその呼び出しを生成する代わりに、関数本体を呼び出しサイトに移動するだけです)。

実験として、関数をstaticではなくとしてマークしてみてくださいinline。これはまた、コンパイラが定義をエクスポートする必要がないことを意味し、インライン展開が価値があると判断する可能性が非常に高くなります。

于 2013-09-21T12:01:45.267 に答える
1

現在 (2018 年)、このinline属性は最適化のためにまだ使用されています。最新のコンパイラでも。

彼らがそれを無視し、代わりに純粋に独自のコスト モデルに依存するという主張は、少なくともオープン ソース コンパイラの GCC と Clang では真実ではありません。Simon Brand は、それについて素晴らしいブログ投稿 ( Do compilers take inline as a Hint? ) を書き、コンパイラのソース コードを見て、その誤りを暴きました。

しかし、これらのコンパイラーが盲目的にプログラマーのヒントに従うわけではありません。パフォーマンスが低下するという十分な証拠があれば、彼らはあなたを却下します。

インライン化を強制するベンダー固有の拡張機能があり、たとえコンパイラがそれを悪い考えだと考えていたとしてもです。たとえば、Visual Studio では次のように呼ばれ__forceinlineます。

キーワードは費用対効果の__forceinline分析よりも優先され、代わりにプログラマーの判断に依存します。を使用する場合は注意してください__forceinline。を無差別に使用すると、__forceinlineコードが大きくなり、パフォーマンスがわずかに向上するだけでなく、場合によってはパフォーマンスが低下することさえあります (たとえば、より大きな実行可能ファイルのページングの増加が原因で)。

GCC と Clang はそれを と呼んでいinline __attribute__ ((__always_inline__))ます。

一般に、特にプロファイルに基づく最適化を使用できる場合は、決定をコンパイラに任せることをお勧めします。強制インライン化を使用する高品質コード ベースの注目すべき例外の 1 つは、Boost です ( を探してくださいBOOST_FORCEINLINE)。

于 2018-12-20T03:48:47.487 に答える
0

あなたが聞き続けていることは間違っているか、間違っているべきです。標準では、次の意図が明確に指定されていますinline。コンパイラがこのコードをインラインで生成できれば望ましいことをコンパイラに伝えます。インライン化が必要な場合、コンパイラーがプログラマーよりも適切に判断できるようになるまでは、「ヒント」を考慮に入れる必要があります。いつの日か、inlineこれとは無関係になるかもしれませregisterんが (なったように)、まだそこには程遠いです。

そうは言っても、あなたのケースで g++ がインライン化されていないことに非常に驚いています。g++ は通常、関数がマークされていない場合でも、インライン化についてかなり積極的ですinline。関数がループに入っていないので、わざわざする価値がないと考えただけかもしれません。

于 2013-09-21T11:56:26.413 に答える