在任何情况下,“首次使用时构建”成语都会失败吗?

时间:2011-09-06 19:54:54

标签: c++ static linker static-initialization

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

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函数以使用'new'但结果完全相同(顺便说一下。程序永远不会崩溃) 但是我不明白它有可能吗?
我有什么不妥的想法吗?

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

  1. 测试完成是单线程环境。
  2. 它适用于某些平台,有些则不适用(适用于Windows,MacOS和AIX,不适用于Linux,HP_UX,Solaris,FreeBSD ......)
  3. 我在执行期间验证了strFilename的地址(在GetString中的printf),看起来它是一个没有重复的变量(地址总是相同的)
  4. 但是,在最终的lib上使用nm我得到类似的东西:
  5. 0000000000000030 T _Z16GetLogprintfFilev
    0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
    0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile
                     U _Z16GetLogprintfFilev

    并且在我的基础库上使用nm(由最终的lib使用),我得到:

    0000000000000030 T _Z16GetLogprintfFilev
    0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
    0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile

2 个答案:

答案 0 :(得分: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()。在大多数系统中,使用单个共享库的加载顺序,但在其他系统上,它将对共享库进行深度优先搜索(即,lib X加载XA XB,Y加载YA YB。搜索顺序可以是X XA XB Y YA YB或XY XA XB YA YB)。您需要查阅每个OS共享库文档,以了解在运行时如何搜索符号。

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

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

答案 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())
  }
}

现在它没有问题。
我似乎很奇怪编译器没有抱怨。
感谢所有人的贡献,问题现在已经解决了。

---------------------------------- EDIT ------------ ----------------------

我后来再次遇到这个问题,所以这不是正确的解决方法 真正的问题是一些初始化的单身人士 在此期间,并在类构造函数中:

GetString() = "";

所以,问题很简单,但很难追踪......