2011-07-27 9 views
8

私は奇妙な問題で何日も過ごし、最後にプロジェクト内に同じ署名の2つの関数があることを発見し、問題を引き起こしました。ここでは、状況を簡略化するためには、一例である2つのCPPファイル:インライン関数を再定義するとどうなりますか?

a.cpp

#include <iostream> 

void b(); 

inline void echo() 
{ 
    std::cout << 0 << std::endl; 
} 

int main() 
{ 
    echo(); 
    b(); 
    return 0; 
} 

とb.cpp

#include <iostream> 

inline void echo() 
{ 
    std::cout << 1 << std::endl; 
} 

void b() 
{ 
    echo(); 
} 

inline機能echoは同じシグネチャを持っていることに注意してくださいが異なります実装する。

g++ a.cpp b.cpp -o a.out && ./a.out 

またはこの

g++ a.cpp -c 
g++ b.cpp -c 
g++ a.o b.o -o a.out 
./a.out 

ようですが0 0を出力をコンパイルして実行します。 (私はG ++そのための4.6.1を使用していた、と私は打ち鳴らす++ 2.9、同じ結果でテスト済み)

g++ -O3 a.cpp b.cpp -o a.out && ./a.out 

のように、最適化をオンにすると、それは0 1今回の場合は発生しません

私の質問は、結果やコンパイルの実行方法に関係なく、私がinline関数を複数回定義したことについてはエラーも警告もありません。このような状況で、コンパイラやリンカには何が起こりますか?

EDIT:

は、両方のファイルがレコードecho()を持って

nm a.o b.o | c++filt 

オブジェクトファイル内のシンボルを見てみましょう。だから問題はリンク時に起こると思う。リンカーがランダムに1つの実装を選択し、他のすべてを破棄したと言えるでしょうか? C++標準で

+0

警告をより詳細に表示しようとしましたか(-Wallなど)? – schnaader

+0

私は '-Wall -Wextra'を試しましたが、まだ警告はありません。 – neuront

答えて

5

コンパイラはこのODR違反を診断する必要はなく、簡単なことではありません。 inlineキーワードは、異なる翻訳単位が同じシンボルを持つ可能性があることを意味し、コンパイラによって弱いとマークされています。基本的な使用例は、ヘッダー内にインラインで定義された関数です。ヘッダを含むすべての変換単位に定義があり、それは完全にうまくいきます。コンパイラは1つの定義以外のすべてを破棄し、その定義をどこでも使用する必要があります。

異なる定義が完全一致であるかどうかを検出することは複雑な問題です。リンカーは、生成されたバイナリ実装を分析し、2つのバイナリコードが同じソースコードに関連するかどうかを判断する必要があります。ほとんどのコンパイラはこれを決定するサポートを持っていません。

あなたの特定の問題のように、私はおそらく、インラインマークされている2つの機能につながった根拠を知ることはできませんが、一般的なエラーがで繰り返しの文句を言わないというより最適化を表現するためにinlineキーワードを使用していますリンク時間inlineキーワードはヘッダーには意味がありますが、cppファイルにはあま​​り意味がありません。 cppファイルで、コードの一部をヘルパー関数に組み入れる場合は、その関数はstaticとマークするか、という名前のない名前空間内に定義する必要があります。関数がstaticの場合、コンパイラはその関数のすべての用途が翻訳単位内にあることを認識しており、関数呼び出しをインライン化するかどうかを判断する知識がますます大きくなります(ただし、あなたがそれを言っても、インラインにしないと決めることができるのと同じ方法でそれを伝えないでください)。

12

インライン関数のすべての定義は同じでなければならないよりも述べられているが、ない診断はが必要です。つまり、あなたのプログラムは有効なC++プログラムではありませんが、実装はそのエラーを検出しない権利があります。

項3.2.5を参照してください。ここに投稿するには長すぎます。

6

この非常にケース(インプリメンテーションが異なる同じ名前と同じシグネチャを持つ2つのインライン関数)leads to undefined behavior。コンパイラはそれを診断する必要はありませんが、試してみることもできます。

関連する問題