C++ Can";“首次使用时建造”;成语在任何情况下都会失败吗?
我正在使用一些静态库构建我的程序(实际上是测试)。C++ Can";“首次使用时建造”;成语在任何情况下都会失败吗?,c++,static,linker,static-initialization,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";
此库包含一个文件,其中包含如下函数:
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”,但结果完全相同(顺便说一句,程序从未崩溃)。
但我不明白这有可能吗?
知道我做错了什么吗?
-------------------------------更新------------------------------------------
0000000000000008 b_zgvz16GetLogPrintOffile16StrLogPrintOffile
00000000000000 18 b_ZZ16GetLogprintfFilevE16strLogprintfFile
U_Z16GetLogprintfFilev 在我的基本库中使用nm(由最终库使用),我得到: 00000000000000 30 T_Z16GetLogprintfFilev
0000000000000008 b_zgvz16GetLogPrintOffile16StrLogPrintOffile
00000000000000 18 b_zz16GetLogPrintffile16StrLogPrintffile
是静态链接时很可能出现这种情况 例如:
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包含一个调用Get getString(),那么将调用哪个版本的getString()是操作系统特有的。在大多数系统上,使用单个共享库的加载顺序,但在其他系统上,它将对共享库进行深度优先搜索(即lib X加载XA XB和Y加载YA YB。搜索顺序可以是X XA XB Y YA YB或X Y XA XB YA YB)。您需要查阅每个OS共享库文档,以了解如何在运行时搜索符号
这里的解决方案是仅针对共享库进行链接(大多数情况下为默认设置)。这样,您只获得一个libA副本(假设您将libA设置为共享lib),其内容只加载到运行时一次(没有副本) 注意:这不是语言级别的失败。
这是由于链接导致的失败,链接超出了C/C++语言的范围。实际上,示例中缺少一个想法。应该是这样的:
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())
}
}
奇怪。无论如何,我将其重构为如下内容:
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() = "";
所以,这个问题很简单,但很难跟踪…顺便问一下,这是您的实际代码还是一个简化的示例?您是否尝试过在调试器中单步执行您的代码,以查看调用的位置以及它们访问的数据?@kuki:嗯,这个简化的示例正如预期的那样工作。因此,结构与实际问题不完全相同。请给出一个简单的例子来重现这个问题。在构造示例时,很可能会发现bug。这段代码很好。您的错误出现在您没有显示给我们的代码中。@kuki:它的工作方式与您发布的不同,即它应该打印“abc”两次。您的代码肯定包含一些其他的bug,当您构建一个复制问题的最小示例时,您会发现这些bug。如果您没有,我们将很乐意在您更新问题时帮助您找到它。或者,我建议您删除这个问题,并在调试代码后发布一个新的带有好例子的问题,但没有发现问题。一、 首先,我投票决定关闭这个库。一开始我的想法完全一样,但我仔细检查了一下,我没有两次链接同一个库。好吧,我想我明天第三次再查…@kuki:如果你能告诉我们确切涉及的图书馆以及它们是如何联系在一起的,那将很有趣。如果您在*nix-like框中,
nm
将转储符号,以便查看GetString()是否位于多个位置。这不要求函数是静态的吗?否则它不应该给出链接器错误吗?@bitmask:不,这是不必要的(但这是实现相同效果的另一种方式)。在上述情况下,每个共享库都是独立的,并且可以有重叠的导出标识符,并且可以成功地与可执行文件链接(链接阶段完全独立于编译,并且只尝试解析符号(而不是重复检测)。@Tux-D:I have shared.lib(其中包含两个函数)另外两个库合并到一个server.lib库中。最后,这个server.lib与测试文件链接。不幸的是,整个过程有点复杂(我们之前正在重新链接server.lib,等等)。我想我会像你说的那样检查nm输出,以及在执行过程中打印出strFilename的地址。更新将在12小时后到来;)很好,你找到了解决方案。接受答案,这样它将被提升到第一位,人们将能够很容易地看到它。我会这样做,但我得到的信息是,我可以明天这样做;)我不认为这解决了问题(它存在)。问题是由链接和加载共享库的方式引起的。你刚刚隐藏了问题。不幸的是,这个问题与