web-dev-qa-db-ja.com

C99マルチファイルプロジェクトでインライン関数を宣言するにはどうすればよいですか?

C99でコンパイルされたプロジェクトでインライン関数を定義したいと思います。どうすればいいですか?ヘッダーファイルで関数を宣言し、.cファイルで詳細を指定すると、定義が他のファイルで認識されません。明示的な関数をヘッダーファイルに入れると、それを使用するすべての.oファイルに定義のコピーがあるため、リンカーで「複数定義」エラーが発生するため、問題が発生します。

私がやろうとしていることは次のようなものです:

header.h
inline void func()
{
    do things...
}


lib1.c
#include "header.h"
...

lib2.c
#include "header.h"

lib1.oとlib2.oの両方を使用するユーティリティを使用

26
mousomer

残念ながら、すべてのコンパイラがその時点でC99に完全に準拠しているわけではありません。

これを行うための適合方法は

// header file. an inline declaration alone is
// not supposed to generate an external symbol
inline void toto(void) {
  // do something
}

// in one .c file, force the creation of an
// external symbol
extern inline void toto(void);

たとえば、gccの新しいバージョンはそれで問題なく動作します。

次のようなものを定義することで、他のコンパイラ(プリテンダー)のためにそれを回避することができます

#ifdef PRETENDER
# define inlDec static
# define inlIns static
#else
# define inlDec 
# define inlIns extern
#endif
// header file. an inline declaration alone is
// not supposed to generate an external symbol
inlDec inline void toto(void) {
  // do something
}

// in one .c file, force the creation of an
// external symbol
inlIns inline void toto(void);

編集:

c99をサポートするコンパイラ(通常はオプション-std=c99)私が知っていること

  • gcc(バージョン> = 4.3 IIRC)は正しいinlineモデルを実装します
  • pccも正しい
  • ggc <4.3には、正しいモデルを実装するための特別なオプションが必要です。そうでない場合は、注意しないと複数のシンボルが定義される独自のモデルが使用されます。
  • 特別な注意を払わない場合、iccはすべてのユニットでシンボルを発行するだけです。ただし、これらのシンボルは「弱い」シンボルであるため、競合は発生しません。彼らはあなたのコードを爆破するだけです。
  • opencc、AFAIRは、古いgcc固有のモデルに従います
  • inline宣言がない限り、clangはextern関数のシンボルをまったく出力しませんおよび 1つのコンパイルユニットで関数ポインタを使用します。
  • tccはinlineキーワードを無視します
26
Jens Gustedt

単独で使用する場合、C99ではinlineは、関数が使用されているのと同じ変換単位で定義されている必要があります(したがって、lib1.cで使用する場合は、lib1.cで定義する必要があります)。

メソッドをstatic inlineとして宣言することもできます(そして、2つのソースファイル間で共有されるヘッダーファイルに定義を入れます)。これにより、複数定義の問題が回避され、コンパイラーは、ファイルが使用されるすべての変換単位にわたってファイルをインライン化できます(1つの変換単位で関数を宣言するだけでは、実行できる場合とできない場合があります)。

参照: http://www.greenend.org.uk/rjk/2003/03/inline.html

4
JonathonW