4

私はマクロを研究していて、マクロとインライン関数の違いに関する多くの情報源と質問を見つけました。しかし、インライン機能と通常の機能の長所と短所を具体的に指定して区別するものはありません。

しかし、通常の機能とインライン機能のどちらかを選択したい場合はどうでしょうか。

インライン関数を使用するとコードサイズが大きくなることを知っています。ただし、サイズの調査は主要な問題ではないため、効率が目標です。関数をインライン関数にすることは、関数の呼び出しが可能な限り高速であることを示唆しています(スタックなどのオーバーヘッドのため)

常にインライン関数を使用する方が良いかどうか?そうでない場合、なぜですか?インラインよりも通常の機能を使用する利点は何ですか?

他の質問を読んでいる間、私はインラインがコンパイラへのヒントにすぎないことを読みました。コンパイラはそれを無視するかもしれません。コンパイラはいつそれを無視し、なぜですか?

4

5 に答える 5

10

関数をインライン化すると、いくつかの利点があります。

  1. プログラムサイズを小さくすることができます。これは通常、関数が 1 回だけ使用される場合です。また、2. と 3. も参照してください。

  2. コンパイラは、変数が定数である、または NULL でない、またはそのようなものであることをコンパイラが認識している場合、関数の未使用ビットを削除できます。これによりサイズを節約できますが、実行時のコードの効率も向上します。

  3. コンパイラは、関数がデータに対して何を行うかを確認できるため、呼び出し関数の一部、または他のインライン関数を削除できます。(コードが戻り値をチェックし、それが NULL の場合はエラー関数を呼び出すとします。それを除外できる可能性があります。

  4. 呼び出しのオーバーヘッドを削減できますが、予測分岐を備えた現在のプロセッサでは、思ったほど効果的ではありません。

  5. ループから定数ビットを引き上げたり、一般的な部分式を削除したり、ループ コードをより効率的にするために他の多くの最適化を行ったりすることができます。

そして、欠点があります:

  1. 明らかに、コードが大きくなる可能性があります。

  2. 呼び出し元の関数内のレジスタ プレッシャが増加し、コンパイラが混乱し、最適化も妨げられる可能性があります。

  3. CPU キャッシュに常駐できるホット関数を 1 つ持つことは、常にキャッシュされるとは限らない多くの場所に複製するよりも高速です。

  4. デバッグを妨げる可能性があります。

インライン関数が単なるヒントである理由は、ほとんどの場合、C 標準ではコンパイラが何かを最適化する必要がないためです。それがヒントでなければ、最適化はオプションではありません。また、関数インラインとマークされていないという理由だけで、インライン化が有利であると計算された場合、コンパイラはインライン化を停止しません。

于 2012-04-12T19:47:57.133 に答える
6

一般に、パフォーマンスが向上すると判断した場合、コンパイラはインライン化を選択します。そのため、非インライン関数を実際に呼び出すコスト (引数をスタックにプッシュする、レジスタを保存するなど) を比較する必要があります。これは、コード自体よりも多くなります。したがって、単純なアクセサーまたは単純な計算の場合、関数を呼び出すコストが高くなることがよくあります。そのため、コンパイラーはインライン化します。

多くの場合、コンパイラにはサイズの制約もあり、インライン化によってコードが大きくなりすぎないようにしています。

考慮すべき地域もあります。インライン化された関数は、ページ フォールトを引き起こしたり、プロセッサ キャッシュ ミスを引き起こしたりする可能性は低いため、一般的にその観点からは高速になります。インライン化されていない関数は、多くの場合、プロセッサ キャッシュにコードをロードする必要がありますが、これは比較すると非常に低速です。

コンパイラが関数をインライン化することを実際には期待していなくても、関数をインライン化することを宣言する理由は他にもあります。C++ の STL 全体はインライン化されていますが、そのほとんどが実際にインライン化される可能性はほとんどありません。これは、テンプレートのインスタンス化や、アプリケーション バイナリ インターフェイスに関する問題などの理由から、この方法で行われます。

于 2012-04-12T19:34:58.300 に答える
2

関数をインライン化する利点は、関数呼び出しのオーバーヘッドを取り除き、オプティマイザーが呼び出しコードを関数コードで最適化する可能性を高めることです。たとえば、オプティマイザは、状況によってはインライン化されたコードを完全に削除する場合があります。

欠点は、ボトルネックが CPU 命令フェッチである場合、特定の状況下で実行速度が遅くなる可能性があるコード サイズが大きくなる可能性があることです。

だからそれは依存します。コンパイラは、さまざまなヒューリスティックを使用して、関数をインライン化することが最終的な利点であるかどうかを判断します。inline キーワードを指定しなくても、コンパイラは関数をインライン化する場合があります。インライン化しても、インライン化されない場合があります。通常、コンパイラに関数をインライン展開させてその決定を無効にする方法があります。

これ関数をインライン化するための優れたヒューリスティックとは何ですか? インライン化ヒューリスティックに関する良い議論とさらなるリンクがあります。

于 2012-04-12T19:31:33.643 に答える
1

インライン関数を使用すると、 が呼び出されたときに関数コードが行に貼り付けられ、インライン関数を使用しない場合よりも大きな実行可能プログラムが生成され、逆に が呼び出されたときにインライン関数が生成されない、プログラムが停止し、関数コードが開始するメモリディレクトリにジャンプします...

結論: インライン関数 = パフォーマンスの向上、スペース関数の増加 = スペースの減少、パフォーマンスのわずかな低下

于 2012-04-12T19:30:29.547 に答える
1

GNU GCCには、gcc のインライン化オプションと決定プロセスのかなり良い概要があります。

これにより、インライン化が不可能なケースが特定されます。「varargs の使用、alloca の使用、可変サイズのデータ​​型の使用、計算された goto の使用、非ローカル goto の使用、およびネストされた関数」

重要な点は非静的関数です。つまり、externリンケージを持つ関数 ( なしで宣言されたすべての関数static) を呼び出すか、そのアドレスを別のソース ファイルに取得することができます。

これにより、コンパイラは「通常の」関数とインライン化された関数本体を強制的に生成します。もちろん、これは「通常の」非インライン関数を生成するだけよりも大きなプログラムを生成します。

Gccには、リンカーが使用されていない関数を削除できるようにするオブジェクトファイルを生成するオプションがあります-ffunction-sectionsが、「... アセンブラーとリンカーはより大きなオブジェクトと実行可能ファイルを作成し、速度も遅くなります。」

gcc の最近のバージョンでは、Link Time Optimisations (LTO) ( 「プログラム全体の最適化」を参照) がサポートされています。これにより、最適化段階でコンパイルされたすべてのプログラムを調べ、さらに積極的なインライン化と最適化を行い、未使用のコードを除外できます。

新しいgcc-4.6 gcc-4.7手続き間の最適化のいくつかを見るのも興味深いことです。たとえば、関数全体ではなく、インライン関数の「ホット パス」のみをインライン化します。定数が既知であるため、Gcc は 1 つの関数の複数のインスタンスを生成することもあり、gcc は、既知の定数に対してそれぞれが最適化された複数の実装を持つ方がよいと計算します。

gcc には、すべての「単純な」関数をインライン化するようコンパイラーに要求するオプションがあります。

最後に、「ISO C ++で必要とされるように、GCCは、クラスの本体内で定義されたメンバー関数が、インラインキーワードで明示的に宣言されていなくても、インラインでマークされていると見なします」と述べています。その場合、「十分に単純」というルールが使用されます。

要約: コンパイラは、通常の関数やインライン関数から期待される以上の非常に巧妙な最適化を行う場合があります。

于 2012-04-12T19:49:01.017 に答える