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


123

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

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

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

回答:


109

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では、関数/変数は同じ変換単位内でのみ使用できます。


4
いいえ、staticスコープを指します。Cでは、関数/変数は同じ変換単位内でのみ使用できます。
littleadv

8
インラインとして宣言されたコードはヘッダーに属していることに注意することも重要です。通常の(非テンプレート)ソースコードは、複数の再定義エラーを引き起こさずにヘッダーに入れることができません。何かをインラインで宣言するときにそうであっても、コンパイラを選択したが、それをインライン化しない場合でも、標準によって義務付けられた複数の再定義を回避動作が依然として存在しているというキックインチ
VoidStar

13
@VoidStar実際static(の有無にかかわらずinline)はヘッダーに完全に含まれている可能性があります。理由はわかりません。テンプレートは、C ++用で、この質問はC.についてです
littleadv

2
@littleadv:ヘッダファイルに関数定義を置くための主な理由は、彼らがINLINABLEようにすることですので、明示的にマーキングすることはinline芋、良いスタイルである
クリストフ・

9
実際にinlineは、インライン化を試みるようコンパイラーに指示していません。プログラマが関数本体を複数の変換単位に含めることができるようにするだけで、ODR違反はありません。これの副作用は、関数インライン化するときに、コンパイラが実際にこれを実行できるようにすることです。
ルスラン

96

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

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

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

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

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

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

inlineそしてregister、彼らはプログラマが最適化が不可能にコードを書き込むときにエラーをスローするようにコンパイラーに指示して、けれども、役に立たないです:外部inline内部リンケージを持つ定義ができない参照識別子(これらは異なる翻訳単位で利用できないだろうと)または、静的ストレージ期間を使用して変更可能なローカル変数を定義します(これらは変換ユニット間で状態を共有しないため)register。また、修飾された変数のアドレスを取得することはできません。

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

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

とはinline異なるストレージクラスで関数を記述したことはありませんstatic


8
これが正解です。inlineインライン化に実際に適用されているかのように話す答えはすべて誤解を招き、間違いなく間違いです。最近のコンパイラは、関数のインライン化を有効にするために、インライン化またはそれを必要とするヒントとしてこれを使用していません。
Tyg13

1
「規約を使用してヘッダーの静的関数定義をインラインでマークする」に賛成。
John Z. Li

21

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

したがって、私はそれをstatic翻訳単位で使用する必要があると思う傾向があり、追加のチェックコンパイラが未使用の関数を見つけるために行うメリットがあります。また、static inline警告を出さずにインライン化できる(外部リンケージがないため)関数を提供するために、ヘッダーファイルで使用する必要があります。

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


うーん、(v8.0.1)でビルドするときに、別の翻訳単位で使用される関数を取得しwarning: unused function 'function' [clang-diagnostic-unused-function]ました。しかし、間違いなく、これは&を組み合わせる最高の説明と理由の1つです。static inlineclang-tidystaticinline
DrumM

6

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

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

編集:

コンパイル単位翻訳単位でなければなりません


2
または派手な言葉で:それは内部のリンケージを持っています。
K-ballo

@AlokSave:コンパイル単位翻訳単位に違いはありますか?もしそうなら、C ++言語の文脈ではどちらがより適切ですか?
legends2k 2013年

私はthe compile unit間違って書いたものだと思います、そのようなことはありません、実際の用語はtranslation unit
shengy

回答は主にヘッダーファイルで使用されており、翻訳単位を超えているため、完全ではありません。
DrumM

5

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


inline定義での使用についてはどうですか?extern関数に使用しないことも意味しますか?
new_perl 2010年

これは、最近のバージョンのGCCでも同じですか?あなたが例を挙げて、どのバージョンのGCCがそれを実行するかをリストした場合、あなたの答えははるかに興味深いでしょう。
Zボソン

@Zboson:すぐに利用できる情報はなく、現時点では多くのgccバージョンをセットアップしてテストする時間もありませんが、役に立つ情報であることに同意します。おそらく、gccが最初に未使用の静的関数/オブジェクトの最適化を開始したときにattribute((used))、その履歴とその使用を調べて、asmが他の参照されていないstatic関数とデータを参照できるようにすることができます。
R .. GitHub ICEのヘルプの停止
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.