web-dev-qa-db-ja.com

extern inline

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

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

「extern inline」は図のどこに収まりますか?

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

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

異なるコンパイラベンダーとバージョン間に違いはありますか?

86
wilbur_m

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 inlineまたはextern inlineの定義はありませんが、多くのコンパイラーには定義があります(通常はgnu89モデルに従っています)。

124
puetzk

この声明に基づいて、__ FILE__と__LINE__を誤解していると思います。

呼び出し元のために解決する必要がある__FILE__および__LINE__マクロを使用しているが、この呼び出された関数ではないため

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

29
Don Neufeld

あなたは次のようなものを書こうとしているようです:

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

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

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

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

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

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...
12
Roddy

インライン、静的インライン、および外部インラインの状況は複雑です。特に、gccとC99の動作(およびおそらくC++)の意味がわずかに異なるためです。 C here でそれらが何をするかについてのいくつかの有用で詳細な情報を見つけることができます。

3
Simon Howard

ここでは、インライン関数ではなくマクロを選択します。マクロがインライン関数を支配するまれな機会。次のことを試してください:この「マクロマジック」コードを書いたので、動作するはずです! 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識別子を(必要に応じて)優先してください。

2

「何をするのか」と答える代わりに、「自分のやりたいことをどうやってやるのか」と答えています。インライン化には5種類あり、すべてGNU C89、標準C99、およびC++で使用できます。

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

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

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

インラインで弱いシンボルを出力します(C++のように、別名「単に動作させる」)

___attribute__((weak))
void foo(void);
inline void foo(void) { ... }
_

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

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

___attribute__((gnu_inline))
extern inline void foo(void) { ... }
_

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

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

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

または、ヒントなしでそれを行うことができます。ヒントは両方の言語で強力なシンボルを発します。

_void foo(void) { ... }
_

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

インラインですべてのTUで放出

_static inline void foo(void) { ... }
_

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

ヘッダーがCとC++の両方から使用される可能性がある場合は、_extern "C"_を忘れないでください!

0
o11c