可以“首次使用时构建”习语在任何情况下都会失败?

发布于 2024-12-03 00:52:36 字数 1409 浏览 1 评论 0原文

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

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

I'm building my program (tests actually) using some static library.
This library contains one file inside which I have functions like that:

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

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

Then in my main.cpp (outside the library) I'm doing:

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

And I get this output:

String: abc
String:

So looks like second call to the function
(but done from different file, which is inside the library)
somehow clear previous value, reinitialize it, or uses own copy of it.
I changed GetString function to use 'new' but result is exactly the same (btw. program never crash).
But I don't understand hot it's possible?
Any ideas what I'm doing wrong?

------------------------------- UPDATE ------------------------------

  1. Test is done is single threaded environment.
  2. It works on some platforms and on some it doesn't (works on windows, MacOS and AIX, doesn't work on linux, HP_UX, Solaris, FreeBSD...)
  3. I verified address of the strFilename during the execution (printf inside GetString) and looks like it's one variable without duplicates (address is always the same)
  4. BUT, with nm on the final lib I get something like that:


0000000000000030 T _Z16GetLogprintfFilev
0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile
U _Z16GetLogprintfFilev

and with nm on my base lib (used by final lib) I get:


0000000000000030 T _Z16GetLogprintfFilev
0000000000000008 b _ZGVZ16GetLogprintfFilevE16strLogprintfFile
0000000000000018 b _ZZ16GetLogprintfFilevE16strLogprintfFile

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浮光之海 2024-12-10 00:52:36

是的,静态链接时这是很有可能的。

示例:

 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)。您需要查阅每个操作系统共享库文档以了解如何在运行时搜索符号。

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

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

Yes this is quite possible when static linking.

Example:

 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()

In the above example if a.out contains a call got getString() it is OS specific which version of getString() will be called. On most systems the load order of the individual shared library is used but on others it will do a depth first search of the shared libraries (ie lib X loads XA XB and Y loads YA YB. search order could be X XA XB Y YA YB or X Y XA XB YA YB). You need to consult each OS shared library documentation to understand how symbols are searched for at runtime.

The solution here is to only link against shared libraries (the default in most situations).
That way you only get one copy of libA (assuming you made libA a shared lib) and its content loaded into runtime only once (with no copies).

Note: This is not a failure at the language level.
This a failure caused by linking which is beyond the scope of the C/C++ language.

離人涙 2024-12-10 00:52:36

实际上,示例中缺少一个想法。它应该看起来像这样:

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() = "";

所以,简单的问题,但真的很难跟踪......

Actually there was one missing think in example. It should look like this:

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

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

Strange. Anyway, I refactored it to something like this:

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

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

And it works without problem now.
Still it seems strange to me that compiler was not complaining.
Thanks to all for their contribution, problem is solved now.

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

I experienced this problem again later so it was not proper fix.
The real problem was some singleton which was initialized
in meantime and had in the class constructor:

GetString() = "";

So, simple problem, but really hard to track...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文