5

我正在使用一些静态库构建我的程序(实际上是测试)。
这个库包含一个文件,其中我有这样的功能:

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:

所以看起来像对函数的第二次调用(但从库内的不同文件完成)以某种方式清除以前的值,重新初始化它,或者使用它自己的副本。
我将 GetString 函数更改为使用“新”,但结果完全相同(顺便说一句,程序永远不会崩溃)。
但我不明白热这可能吗?
任何想法我做错了什么?

- - - - - - - - - - - - - - - - 更新 - - - - - - - - - ------------

  1. 测试完成是单线程环境。
  2. 它适用于某些平台,有些则不适用(适用于 windows、MacOS 和 AIX,不适用于 linux、HP_UX、Solaris、FreeBSD...)
  3. 我在执行期间验证了 strFilename 的地址(GetString 中的 printf),看起来它是一个没有重复的变量(地址始终相同)
  4. 但是,在最终的库中使用 nm 我会得到类似的结果:

0000000000000030 T _Z16GetLogprintfFilev
0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile
U _Z16GetLogprintfFilev

在我的基础库上使用 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 包含调用 got getString() ,则将调用哪个版本的 getString() 取决于操作系统。在大多数系统上,使用单个共享库的加载顺序,但在其他系统上,它将对共享库进行深度优先搜索(即 lib X 加载 XA XB 和 Y 加载 YA YB。搜索顺序可以是 X XA XB Y YA YB或 XY XA XB YA YB)。您需要查阅每个 OS 共享库文档以了解在运行时如何搜索符号。

这里的解决方案是只链接共享库(大多数情况下的默认值)。
这样,您只能获得一份 libA 副本(假设您将 libA 设为共享库),并且其内容仅加载到运行时一次(没有副本)。

注意:这不是语言层面的失败。
这是由超出 C/C++ 语言范围的链接导致的失败。

于 2011-09-06T20:09:04.420 回答
-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 回答