3

最近、私のプロジェクトで問題が発生しました。通常は gcc-4 でコンパイルしますが、gcc-3 でコンパイルしようとすると、インライン関数の扱いが異なることに気付きました。これを説明するために、簡単な例を作成しました。

main.c:

#include "header.h"
#include <stdio.h>

int main()
{
    printf("f() %i\n", f());
    return 0;
}

file.c:

#include "header.h"
int some_function()
{
    return f();
}

header.h

inline int f()
{
    return 2;
}

gcc-3.4.6 でコードをコンパイルすると:

gcc main.c file.c -std=c99 -O2

-O2リンカー エラー (f の複数定義) が発生します。フラグを削除しても同じです。コンパイラは、インライン化したくない場合は何もインライン化する必要がないことを知っているので、 と の両方の場合、インライン化する代わりに f をオブジェクト ファイルに配置すると仮定したため、main.c複数file.cの定義エラーが発生しました。明らかに、f静的にすることでこれを修正できます。最悪の場合、fバイナリにいくつかの があります。

しかし、私はこのコードをgcc-4.3.5でコンパイルしようとしました:

gcc main.c file.c -std=c99 -O2

fそして、すべてが正常に機能したので、どちらの場合も新しい gcc がインライン化さfれ、バイナリに関数がまったくないと想定しました (gdb でチェックしたところ、私は正しかった)。

ただし、-O2フラグを削除すると、 への未定義の参照が 2 つ取得されましたint f()。そして、ここで、何が起こっているのか本当にわかりません。gcc はfインライン化されると想定していたようで、オブジェクト ファイルに追加しませんでしたが、後で ( がなかったため-O2) インライン化する代わりにこれらの関数の呼び出しを生成することを決定し、そこからリンカー エラーが発生しました。

さまざまなコンパイラでの問題を恐れずにプロジェクト全体で使用できるように、インラインで必要な単純で小さな関数をどのように定義および宣言すればよいでしょうか。そして、それらすべてを静的にするのは正しいことですか? それとも、gcc-4 が壊れていて、静的でない限り、いくつかの翻訳単位でインライン関数の複数の定義を使用するべきではありませんか?

4

1 に答える 1

5

はい、動作は gcc-4.3 以降で変更されました。gcc インライン ドキュメント ( http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Inline.html ) で詳細が説明されています。

短い話: 単純なインラインは、gcc (古いバージョンでは) に同じファイル スコープからの呼び出しをインライン化するように指示するだけです。ただし、すべての呼び出し元がファイル スコープからのものであることを gcc に通知しないため、gcc はリンク可能なバージョンの f()around: も保持します。これにより、上記の重複シンボル エラーが説明されます。

Gcc 4.3 では、この動作が c99 と互換性を持つように変更されました。

そして、あなたの特定の質問に答えるには:

さまざまなコンパイラでの問題を恐れずにプロジェクト全体で使用できるように、インラインで必要な単純で小さな関数をどのように定義および宣言すればよいでしょうか。そして、それらすべてを静的にするのは正しいことですか? それとも、gcc-4 が壊れていて、静的でない限り、いくつかの翻訳単位でインライン関数の複数の定義を使用するべきではありませんか?

gcc バージョン間の移植性が必要な場合は、静的インラインを使用してください。

于 2010-06-23T09:44:29.280 に答える