5

静的ライブラリを使用してプログラムを構築しています(実際にテストします)。
このライブラリには、次のような関数を含む1つのファイルが含まれています。

string& GetString() {
    static string strFilename;
    return strFilename;
}

void PrintToScreen() {
    printf("String: %s\n", GetString().c_str())
}

次に、main.cpp(ライブラリの外)で次のことを行っています。

GetString() = "abc";
printf("String: %s\n", GetString().c_str());
PrintToScreen();

そして、私はこの出力を取得します:

String: abc
String:

したがって、関数の2番目の呼び出し(ただし、ライブラリ内にある別のファイルから実行)は、以前の値をクリアするか、再初期化するか、独自のコピーを使用するように見えます。
GetString関数を「new」を使用するように変更しましたが、結果はまったく同じです(ところで、プログラムがクラッシュすることはありません)。
しかし、私はそれが可能であるかを理解していませんか?
私が間違っていることについて何か考えはありますか?

- - - - - - - - - - - - - - - - アップデート - - - - - - - - - ------------

  1. テストはシングルスレッド環境で行われます。
  2. 一部のプラットフォームでは動作し、一部では動作しません(Windows、MacOS、AIXで動作し、Linux、HP_UX、Solaris、FreeBSDでは動作しません...)
  3. 実行中にstrFilenameのアドレス(GetString内のprintf)を確認しましたが、重複のない1つの変数のように見えます(アドレスは常に同じです)
  4. しかし、最後のライブラリにnmがあると、次のようになります。

0000000000000030 T _Z16GetLogprintfFilev
0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile
U _Z16GetLogprintfFilev

そして、ベースライブラリ(final libで使用)にnmを使用すると、次のようになります。

0000000000000030 T _Z16GetLogprintfFilev
0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile

4

2 に答える 2

3

はい、これは静的リンクの場合に非常に可能です。

例:

 libA.a   // contains GetString()
          // Contains. PrintToScreen()
          // Here the reference has been resolved.

 libX.so  // Contains a call to GetString()
          // This library is linked with libA.a
          // Thus pulls in the function GetString() into this library.

 libY.so  // Contains a call to PrintToScreen()
          // This library is linked with libA.a
          // Thus pulls in the function PrintToScreen and GetString() into this library.

 a.out    // linked against libY.so libX.so
          // This has two distinct versions of GetString()

上記の例では、a.outにgetString()の呼び出しが含まれている場合、どのバージョンのgetString()が呼び出されるかはOS固有です。ほとんどのシステムでは、個々の共有ライブラリのロード順序が使用されますが、他のシステムでは、共有ライブラリの深さ優先探索が実行されます(つまり、libXはXAXBをロードし、YはYAYBをロードします。検索順序はXXA XB YYAYBである可能性があります。またはXYXAXB YA YB)。実行時にシンボルがどのように検索されるかを理解するには、各OS共有ライブラリのドキュメントを参照する必要があります。

ここでの解決策は、共有ライブラリ(ほとんどの状況でのデフォルト)に対してのみリンクすることです。
そうすれば、libAのコピーを1つだけ取得し(libAを共有ライブラリにしたと仮定)、そのコンテンツをランタイムに1回だけロードします(コピーはありません)。

注:これは言語レベルでの失敗ではありません。
これは、C /C++言語の範囲を超えているリンクによって引き起こされた失敗です。

于 2011-09-06T20:09:04.420 に答える
-1

実際、例として1つ欠けている考えがありました。次のようになります。

string& GetString() {
  static string strFilename;
  return strFilename;
}

extern "C" {
  void PrintToScreen() {
    printf("String: %s\n", GetString().c_str())
  }
}

変。とにかく、私はそれを次のようなものにリファクタリングしました:

extern "C" {
  string* GetString() {
    static string strFilename;
    return &strFilename;
  }

  void PrintToScreen() {
    printf("String: %s\n", GetString()->c_str())
  }
}

そして今は問題なく動作します。
それでも、コンパイラが文句を言っていなかったのは奇妙に思えます。
皆さまのご協力に感謝し、問題は解決しました。

- - - - - - - - - - - - - - - - - 編集 - - - - - - - - -------------------

後でこの問題が再び発生したため、適切な修正ではありませんでした。
本当の問題は
、その間に初期化され、クラスコンストラクターにあるシングルトンでした。

GetString() = "";

だから、単純な問題ですが、追跡するのは本当に難しいです...

于 2011-09-07T11:59:02.887 に答える