5

ヘッダーでインライン関数を定義する共有ライブラリを使用しています。

これは、ライブラリにリンクしているコンパイルユニットから見た、縮小されたテストケースです(ライブラリから見たバージョンの場合は、に置き換えdllimportdllexportください)。

class __declspec(dllimport) MyClass {
public:
    int myFunc2();
    int myFunc1();
};

inline int MyClass::myFunc2(void) {
    return myFunc1();
}

inline int MyClass::myFunc1(void) {
    return 0;
}

これをコンパイルすると、警告が表示されます。

警告:'int MyClass :: myFunc1()' dllリンケージで参照された後、dllimport属性なしで再宣言されました[デフォルトで有効]

myFunc1結果の定義の前にの定義を置くと警告が表示されないため、関数が定義される順序が重要であることに注意してくださいmyFunc2

このコードは、VisualC++では警告なしにコンパイルされることにも注意してください。これらの警告は、少なくともMinGWに固有のものであり、おそらくGCC全般に固有のものです。編集:プロジェクトによって設定されたフラグの1つによって警告が抑制されていないかどうかを確認する必要があるかもしれないことに気づきました。

私の質問は次のとおりです。

  • なぜこの振る舞い?
  • クラス宣言内で宣言すると、問題が修正myFunc1されます。inline何故ですか ?また、推奨される方法にも反します。
  • この問題を解決する別の(より良い?)方法はありますか?
4

2 に答える 2

6

この問題は、dllimportが機能する方法の魔法が原因で発生します。これは通常、最初の宣言でのみ必要になることを意味します。

基本的に、関数をdllimportとして宣言し、後でdllimportを除いて同じ宣言で関数を再宣言すると、2番目の宣言は暗黙的にdllimportを取得します。再宣言が同一でない場合、暗黙のdllimportを取得しません。

したがって、ここで行われるのは、最初に関数をdllimport / non-inlineとして宣言し、次にそれをnon-dllimport/inlineとして宣言することです。最初の宣言にインラインを追加すると、2番目の宣言が暗黙的にdllimportになるため、問題が修正されます。または、2番目の宣言にaを追加する__declspec(dllimport)と、問題が修正されます。

警告は再宣言する前に使用することに関するものであるため、定義を並べ替えると警告が削除されることに注意してください。再注文すると、再宣言の前に使用しなくなるため、dllimport以外のバージョンが使用されますが、警告は表示されません(つまり、dllの関数のバージョンは使用されません)。

また、インラインdllimportの使用は危険です。dllに対して構築されたプログラムは、ある場所ではインライン関数を使用し、他の場所では(dllからの)非インライン関数を使用する場合があります。現在、2つの関数が同一であっても、dllの将来のバージョンが変更され、実装が異なる可能性があります。その時点で、新しいバージョンのdllを使用して実行すると、古いプログラムが誤動作し始める可能性があります。

于 2012-07-18T21:30:55.063 に答える
3

クリス・ドッドの答えへのさらなる情報:

MSVC2017とMinGW-w647.2.0でテストしました。どちらの場合も、最適化を有効にすると、警告にもかかわらず、 myFunc1()fromの呼び出しがmyFunc2解決されてインラインバージョンになります。の本体myFunc1を下に移動してもmain()

したがって、私の暫定的な結論は、この警告を無視しても安全であるということです。


クリーンコンパイルのために、MinGW-w64で機能すると思われる唯一のメソッドは、クラス定義内の関数宣言をとしてマークすることinlineです。__declspec(dllimport)コンパイラは、クラス外の関数定義に適用することを許可しません。

この警告を明確に無効にするg++の警告フラグがあるかどうかを判断できませんでした。

于 2018-03-02T03:11:07.623 に答える