web-dev-qa-db-ja.com

「静的」機能と「静的インライン」機能の違いは何ですか?

IMOは両方とも、関数が翻訳単位のみのスコープを持つようにします。

「静的」機能と「静的インライン」機能の違いは何ですか?

.cファイルではなく、ヘッダーファイルにinlineを配置する必要があるのはなぜですか?

112
new_perl

inlineは、実際の呼び出しを実行する代わりに、呼び出しコードに関数の内容を埋め込む試行をコンパイラーに指示します。

頻繁に呼び出される小さな関数の場合、パフォーマンスに大きな違いが生じる可能性があります。

ただし、これは単なる「ヒント」であり、コンパイラはそれを無視する可能性があり、ほとんどのコンパイラは、可能な場合、最適化の一部としてキーワードが使用されていない場合でも「インライン」を試みます。

例えば:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

このタイトなループは、各反復で関数呼び出しを実行します。実際、関数の内容は、呼び出しを実行するためにコンパイラが配置する必要があるコードよりも大幅に少なくなります。 inlineは本質的に、上記のコードを同等のものに変換するようコンパイラーに指示します。

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

実際の関数呼び出しをスキップして戻る

明らかに、これはポイントを示すための例であり、実際のコードではありません。

staticはスコープを指します。 Cでは、関数/変数は同じ変換単位内でのみ使用できることを意味します。

95
littleadv

デフォルトでは、インライン定義は現在の翻訳単位でのみ有効です。

ストレージクラスがexternの場合、識別子には外部リンケージがあり、インライン定義も外部定義を提供します。

ストレージクラスがstaticの場合、識別子には内部リンケージがあり、インライン定義は他の翻訳単位では見えません。

ストレージクラスが指定されていない場合、インライン定義は現在の翻訳単位でのみ表示されますが、識別子にはまだ外部リンケージがあり、外部定義は別の翻訳単位で提供する必要があります。コンパイラーは、関数が現在の変換単位内で呼び出される場合、インライン定義または外部定義を自由に使用できます。

コンパイラーは、定義が現在の翻訳単位で表示される関数を自由にインライン化できます(インライン化できません)(また、リンク時最適化のおかげで、異なる翻訳単位でも、C標準では実際には考慮されません)それ)、ほとんどの実用的な目的のために、staticstatic inline関数の定義に違いはありません。

inline指定子(registerストレージクラスなど)は単なるコンパイラヒントであり、コンパイラはそれを完全に無視できます。標準に準拠した非最適化コンパイラは副作用を尊重するだけでよく、最適化コンパイラは明示的なヒントの有無にかかわらずこれらの最適化を行います。

inlineregisterは、プログラマが最適化を不可能にするコードを記述するときにコンパイラにエラーをスローするよう指示するため、役に立たないわけではありません。外部inline定義は識別子を参照できません内部リンケージ(これらは別の翻訳単位では使用できないため)または静的ストレージ期間で変更可能なローカル変数を定義するため(これらは翻訳単位間で状態を共有しないため)、registerのアドレスを取ることはできません修飾された変数。

個人的には、ヘッダー内のstatic関数定義もinlineとマークする規則を使用します。ヘッダーファイルに関数定義を置く主な理由は、それらをインライン化できないようにするためです。

一般に、ヘッダー内のextern宣言に加えて、static inline関数とstatic constオブジェクト定義のみを使用します。

inlineとは異なるストレージクラスを持つstatic関数を書いたことはありません。

72
Christoph

GCCでの経験から、staticstatic inlineは、コンパイラが未使用の関数に関する警告を発行する方法が異なることを知っています。より正確にstatic関数を宣言し、現在の翻訳単位で使用されていない場合、コンパイラは未使用の関数に関する警告を生成しますが、static inlineに変更することで警告を禁止できます。

したがって、私はstaticが翻訳単位で使用されるべきであると考えがちであり、余分なチェックコンパイラが未使用の関数を見つけるのに役立ちます。また、static inlineをヘッダーファイルで使用して、警告を発行せずに(外部リンクがないため)インライン化できる関数を提供する必要があります。

残念ながら、私はその論理の証拠を見つけることができません。 GCCのドキュメントからでも、inlineは未使用の関数警告を禁止すると結論付けることはできませんでした。誰かがその説明へのリンクを共有してくれたら幸いです。

16
ony

Cでは、staticは、定義する関数または変数がこのファイルでのみ使用できることを意味します(つまり、コンパイル単位)

したがって、static inlineは、このファイルでのみ使用できるインライン関数を意味します。

編集:

コンパイル単位翻訳単位

5
shengy

言語レベルではなく、一般的な実装レベルにある1つの違い:gccの特定のバージョンは、参照されないstatic inline関数をデフォルトで出力から削除しますが、参照されない場合でもプレーンstatic関数を保持します。これがどのバージョンに当てはまるかはわかりませんが、実用的な観点からは、ヘッダーのinline関数に常にstaticを使用することをお勧めします。

5
R..