ProgrammingC/C++エンジニア

Cにおけるインラインで宣言された関数と通常の関数の違いについて教えてください。複数のソースファイルで作業する際にインライン関数を正しく宣言するための制限はどのようなものですか。また、開発者がよく犯す間違いは何ですか?

Hintsage AIアシスタントで面接を突破

回答

inline は、関数の呼び出しをその本体(コードの挿入)に置き換えるようコンパイラにヒントを与えます。これにより実行を高速化できる場合があります(呼び出しのオーバーヘッドがないため)が、バイナリサイズの増加を引き起こす可能性があります。

構文:

inline int square(int x) { return x * x; }

コンパイラはインラインを無視する権利があります。異なるファイルで関数の同時使用と実装を行う場合は、次のようにします:

// header.h inline int min(int a, int b) { return a < b ? a : b; }

関数の本体は、インライン関数が呼び出されるすべてのファイルでアクセス可能でなければなりません。つまり、通常の方法は関数をヘッダーファイルで定義することです。

インライン関数を1つの.cファイルだけに宣言および定義すると、他のモジュールでは使用できず、リンキングエラー(undefined reference)が発生します。

ひっかけ質問

ヘッダーファイルでのこれらの宣言の違いは何ですか?

inline int foo(int x) { return x + 1; } static inline int bar(int x) { return x + 1; }

回答:

  • inline int foo(...) は、関数が多数の弱い定義を持つ可能性があるため(one definition rule)、複数の.cファイルが同じヘッダーをインクルードすると、リンクエラーが発生する可能性があります。
  • static inline は、各モジュールに対して関数を内部的にします:各接続ポイントはそれぞれのコピーを得るため、リンク時に問題は発生しません。これがヘッダー内のインライン関数にとって最も安全です。

実際のエラーの例


物語

数学関数ライブラリで、多くのインラインヘルパーを.cファイルで定義しました。他のモジュールからそれらを使用しようとすると、定義が1つのオブジェクトファイルでのみ見えるため、リンキングエラーが発生しました。


物語

インライン関数を.cファイルからヘッダーに移動した後、プロジェクトはリンキング時にクラッシュしました:リンカーは同じ関数の複数の定義について訴えました。ヘッダーファイルで static inline に置き換えることで解決しました。


物語

内部アルゴリズムの最適化において、「クリティカル」な関数にインラインを使用し、高速化を期待していました。しかし、コンパイラはヒントを無視し、プロファイラは呼び出しコストが低下しなかったことを示しました。この問題は、コンパイラの最適化オプションを手動で分析することでのみ解決しました。