3

このユーザー エラーの一貫性のないクラッシュの舞台裏の原因を誰かが説明してくれませんか。

主な機能はこちら

#include "foo.h"  
inline int Bar(const int &a)  
{  
...  
}  
...  
int b=Bar(a);

「foo.C」には、関数のコピーもあります

inline int Bar(const int &a) 

これが問題です。私は foo.h も foo.C も所有しておらず、foo.h に Bar(int) の宣言がありません。古いバージョンの foo.h と foo.C ですべてがコンパイル
され、正常に動作する 同僚が foo.C の他の関数を更新した後、コードは正常にコンパイルされますが、実行時にクラッシュし始めました。
ddd を介してデバッグすると、メイン関数が Bar() を呼び出すと、実際には自分で定義した Bar() ではなく foo.C 内で Bar() を呼び出していることがわかりました。
原因の修正は、自分の関数を静的にするか、自分の Bar() 関数の名前を変更することでした。

このようなコードを書くとまとまりがなく、このようなエラーが発生しやすいことを私は知っています。誰かがなぜコードが矛盾してクラッシュするのか説明してもらえますか?

皆さん、ありがとうございました

よろしく

4

2 に答える 2

2

インライン関数にはまだ外部リンケージがあります。つまり、それらはコンパイラによって対応するオブジェクト ファイルに出力され、リンカーがアプリケーションをリンクすると、同じシグネチャ (名前とそれを囲む名前空間を含む) を持つすべての関数が同じであると見なされます。関数は定義されているためinline、定義の 1 つをランダムに選択し、エラーなしで他の定義を削除します。(これは1 つの定義規則に違反しており、標準に従って未定義の動作を引き起こします。)

この問題を防ぐには、次のように匿名名前空間を使用します。

namespace {
inline int Bar(const int &a)  
{  
...  
}  
}

あなたの場合、foo.Cまたはmainのいずれかでそうすることでうまくいきます。同様に、次を追加できますstatic

static int Bar() {}

Cで書いていたら.

匿名の名前空間またはstaticキーワードを使用すると、関数が翻訳単位に対してローカルになるため、リンカーはそれを外部シンボルとして認識しません。このようにして、異なる翻訳単位で同じ署名を持つ任意の量の関数を使用できます。

于 2012-07-13T20:51:57.527 に答える
0

独自の Bar 関数を定義する前に foo.h を介して #include されているため、foo で定義された Bar 関数を使用していると思います。

コンパイラが重複した定義 (違法) について警告していないことに驚きましたが、#include "foo.h" の前に Bar 関数を定義していた場合、エラーが発生するはずでした。

この URL は、インラインが同じでない限り、インラインの再定義は違法であると述べています。

C 静的インライン関数の再定義規則

私のコンパイラはこれでエラーをスローしています。回避する最善の方法は、別の名前空間またはマクロ ガードを使用することです。

于 2012-07-13T20:52:30.590 に答える