102

inlineそれ自体がコンパイラへの提案であり、その裁量で関数をインライン化する場合としない場合があり、リンク可能なオブジェクト コードも生成されることを理解しています。

私はそれstatic inlineが同じことをすると思います(インライン化される場合とされない場合があります)が、インライン化されたときにリンク可能なオブジェクトコードを生成しません(他のモジュールがそれにリンクできないため)。

写真のどこextern inlineに当てはまりますか?

プリプロセッサ マクロをインライン関数で置き換えたいと仮定し、この関数をインライン化する必要があるとします (たとえば、呼び出された関数ではなく、呼び出し元に対して解決する必要がある__FILE__およびマクロを使用するため)。__LINE__つまり、関数がインライン化されない場合に備えて、コンパイラまたはリンカーのエラーを確認したいと考えています。extern inlineこれを行いますか?(そうでない場合、マクロに固執する以外にこの動作を実現する方法はないと思います。)

C++ と C の間に違いはありますか?

コンパイラのベンダーやバージョンによって違いはありますか?

4

6 に答える 6

139

K&R C または C89 では、インラインは言語の一部ではありませんでした。多くのコンパイラはこれを拡張機能として実装しましたが、それがどのように機能するかについて定義されたセマンティクスはありませんでした。GCC はインライン化を最初に実装したものの 1 つであり、inlinestatic inline、およびextern inline構造を導入しました。ほとんどの C99 より前のコンパイラは、一般にそのリードに従います。

GNU89:

  • inline: 関数はインライン化されている可能性があります (これは単なるヒントです)。アウトオブライン バージョンは常に出力され、外部から見えます。したがって、このようなインラインは 1 つのコンパイル単位でしか定義できず、他のすべてのコンパイル単位はそれをアウトオブライン関数として見る必要があります (そうしないと、リンク時に重複したシンボルが得られます)。
  • extern inlineは、アウトオブライン バージョンを生成しませんが、それを呼び出す可能性があります (したがって、他のコンパイル単位で定義する必要があります。ただし、1 つの定義のルールが適用されます。アウトオブライン バージョンは、コンパイラが代わりにそれを呼び出す場合に備えて、ここで提供されるインライン。
  • static inlineファイル静的バージョンを生成する可能性がありますが、外部から見えるアウトオブライン バージョンは生成しません。発行された外部シンボルも外部シンボルへの呼び出しもないため、1 つの定義ルールは適用されません。

C99 (または GNU99):

  • inline: GNU89 のような "extern inline"; 外部から見える関数は発行されませんが、呼び出される可能性があるため、存在する必要があります
  • extern inline: GNU89 のように「インライン」: 外部から見えるコードが出力されるため、これを使用できる翻訳単位は最大で 1 つです。
  • static inline: GNU89 の「静的インライン」のように。これは、gnu89 と c99 の間で唯一の移植可能なものです。

C++:

どこでもインラインである関数は、同じ定義でどこでもインラインでなければなりません。コンパイラ/リンカーは、シンボルの複数のインスタンスを分類します。static inlineorの定義はありませんがextern inline、多くのコンパイラには定義があります (通常は gnu89 モデルに従っています)。

于 2008-10-19T15:35:07.343 に答える
32

次のステートメントに基づいて、__FILE__ と __LINE__ を誤解していると思います。

__FILE__ および __LINE__ マクロを使用しているため、呼び出し元では解決されますが、この呼び出された関数では解決されません。

コンパイルにはいくつかのフェーズがあり、前処理が最初です。__FILE__ と __LINE__ は、そのフェーズで置き換えられます。そのため、コンパイラが関数をインライン化することを検討できるようになるまでに、関数は既に置き換えられています。

于 2008-10-19T15:15:57.320 に答える
14

次のようなものを書き込もうとしているようです。

inline void printLocation()
{
  cout <<"You're at " __FILE__ ", line number" __LINE__;
}

{
...
  printLocation();
...
  printLocation();
...
  printLocation();

毎回異なる値が出力されることを願っています。__FILE__ と __LINE__ はプリプロセッサによって実装されますが、インラインはコンパイラによって実装されるためです。したがって、どこから printLocation を呼び出しても、同じ結果が得られます。

これを機能させる唯一の方法は、printLocation をマクロにすることです。(はい、知っています...)

#define PRINT_LOCATION  {cout <<"You're at " __FILE__ ", line number" __LINE__}

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...
于 2008-10-19T21:49:24.763 に答える
4

「それは何をしますか?」と答える代わりに、「どうすれば自分のやりたいことをさせることができるか?」と答えています。インライン化には 5 種類あり、すべて GNU C89、標準 C99、および C++ で使用できます。MSVC にはそれらのいくつかがあります (MSVC コードをテストしていないことに注意してください)。

アドレスが取得されない限り、常にインライン

任意の宣言に追加__attribute__((always_inline))し、以下のいずれかのケースを使用して、そのアドレスが取得される可能性を処理します。

セマンティクスが必要でない限り (たとえば、特定の方法でアセンブリに影響を与える、または を使用するalloca)、おそらくこれを使用しないでください。コンパイラは通常、それが価値があるかどうかをあなたよりもよく知っています。

MSVC には__forceinlineほとんど同じように見えますが、他のコンパイラが適切に管理するかなりの数の一般的な状況 (最適化がオフの場合など) でインライン展開を拒否しているようです。

インライン化して弱いシンボルを発行する (C++ のように、別名「動作させるだけ」)

__attribute__((weak))
void foo(void);
inline void foo(void) { ... }

これにより、同じコードのコピーがたくさん残り、リンカが任意に 1 つを選択することに注意してください。

MSVC は、C モードで正確に同等のものを持っているようには見えませんが、似たようなものがいくつかあります。__declspec(selectany)データのみについて話しているように見えるので、関数には当てはまらないのでしょうか? 弱いエイリアスのリンカー サポートもありますが、ここでは機能しますか?

インライン、ただしシンボルを発行しない (外部参照を残す)

__attribute__((gnu_inline))
extern inline void foo(void) { ... }

MSVC の__declspec(dllimport)は、実際の定義 (それ以外の場合は異常) と組み合わされて、おそらくこれを行います。

常に発行する (1 つの TU に対して、上記を解決するため)

ヒント付きバージョンは、C++ では弱いシンボルを出力しますが、C のいずれかの方言では強いシンボルを出力します。

void foo(void);
inline void foo(void) { ... }

または、両方の言語で強力なシンボルを出力するヒントなしで実行できます。

void foo(void) { ... }

一般に、定義を提供するときに TU がどの言語であるかを知っているので、インライン展開はおそらくあまり必要ありません。

MSVC__declspec(dllexport)はおそらくこれを行います。

すべてのTUでインライン化して発行する

static inline void foo(void) { ... }

1 つを除くこれらすべてについて、上記の宣言staticを追加できます。これは、クリーンなヘッダーを作成し、インライン定義を含む別のファイルをvoid foo(void)作成するという「ベスト プラクティス」に役立ちます。#include次に、C スタイルのインラインを使用している場合#defineは、1 つの専用 TU でいくつかのマクロを異なる方法で実行して、アウト オブ ライン定義を提供します。

extern "C"ヘッダーが C と C++ の両方から使用される可能性があるかどうかを忘れないでください。


関連するものもいくつかあります。

決してインライン化しない

__attribute__((noinline))関数の任意の宣言に追加します。

MSVC にはあり__declspec(noinline)ますが、メンバー関数でのみ機能することが文書化されています。ただし、インライン化を妨げる可能性のある「セキュリティ属性」についての言及を見たことがありますか?

可能であれば、他の関数をこれにインライン化するよう強制します。

__attribute__((flatten))関数の任意の宣言に追加します。

noinlineコンパイル時に定義がわからない関数と同様に、これよりも強力であることに注意してください。

MSVC には同等のものはないようです。[[msvc::forceinline_calls]](ステートメントまたはブロックに適用された)の単一の言及を見たことがありますが、再帰的ではありません。

于 2018-07-08T07:02:06.677 に答える
3

ここでは、インライン関数ではなくマクロを選択します。マクロがインライン関数を支配するまれなケース。次のことを試してください: この「MACRO MAGIC」コードを書きましたが、動作するはずです! gcc/g++ Ubuntu 10.04 でテスト済み

//(c) 2012 enthusiasticgeek (LOGGING example for StackOverflow)

#ifdef __cplusplus

#include <cstdio>
#include <cstring>

#else

#include <stdio.h>
#include <string.h>

#endif

//=========== MACRO MAGIC BEGINS ============

//Trim full file path
#define __SFILE__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__ )

#define STRINGIFY_N(x) #x
#define TOSTRING_N(x) STRINGIFY_N(x)
#define _LINE (TOSTRING_N(__LINE__))

#define LOG(x, s...) printf("(%s:%s:%s)"  x "\n" , __SFILE__, __func__, _LINE, ## s);

//=========== MACRO MAGIC ENDS ============

int main (int argc, char** argv) {

  LOG("Greetings StackOverflow! - from enthusiasticgeek\n");

  return 0;
}

複数のファイルの場合、これらのマクロを別のヘッダー ファイルに定義し、各 c/cc/cxx/cpp ファイルに同じものを含めます。可能な限り、マクロよりもインライン関数または const 識別子 (場合によっては) を優先してください。

于 2012-08-06T21:32:48.457 に答える
3

inline、static inline、および extern inline の状況は複雑です。特に、gcc と C99 では、それらの動作 (およびおそらく C++ も同様) に対してわずかに異なる意味が定義されているためです。それらが C で何をするかについての有用で詳細な情報をここで見つけることができます。

于 2008-10-19T21:59:14.040 に答える