我在c ++共享库项目中遇到全局变量问题。我的库必须作为标准的g ++共享库(.so)和一个DLL工作。我这样做是通过创建文件libiup_dll.cpp和libiup_dll.h,其中我有类似的东西
#ifdef BUILD_DLL
// code for the dll: wrapper functions around the classes in my shared library
#endif
在我的dll中,我需要函数setloglevel(int)和geterrormsg()。在我的所有类中,然后我将附加一个全局变量errormsg所有错误消息。然后,geterrormsg()函数应返回此变量。我通过使用
实现了这一点std::string errormsg;
int loglevel;
在libiup_dll.h中(外部和#ifdefs,因此它应该是全局可用的),然后放入
extern std::string errormsg;
extern int loglevel;
在我的班级.h文件中(课外,文件顶部)
现在我有两个问题:
1)用g ++编译命令行程序时,使用我的库,我得到错误
构建目标:libiup_test调用: GCC C ++ Linker g ++ -L“/ home / hilboll / src / libiup / Release”-L / usr / local / lib -o“libiup_test”./ src /stratcalc / SimpleStratosphericColumnCalculatorTest.o ./src/interp/SimpleInterpolatorTest.o ./src/Test.o -lgsl -lhdf5 -lhdf5_cpp -lblas -liup /home/hilboll/src/libiup/Release/libiup.so: 对
loglevel' /home/hilboll/src/libiup/Release/libiup.so: undefined reference to
errormsg'的未定义引用 collect2:ld返回1退出状态 make:*** [libiup_test]错误1
即使在我的命令行程序中,也没有对errormsg或loglevel的任何引用。
2)当尝试使用VS2008在windows下编译dll时,我得到了
Z:\ SRC \ VS \ libiup_dll \ libiup_dll.h(229) :错误C2086:'std :: string errormsg': Neudefinition Z:\ SRC \ libiup \ SRC \ stratcalc ../的interp / SimpleInterpolator.h(16): Siehe Deklaration von'errormsg' Z:\ SRC \ VS \ libiup_dll \ libiup_dll.h(234) :错误C2086:'int loglevel': Neudefinition Z:\ SRC \ libiup \ SRC \ stratcalc ../的interp / SimpleInterpolator.h(17): Siehe Deklaration von'loglevel'
据我所知,这意味着VS认为我将两个变量定义为两次。但是,在SimpleInterpolator.h 16/17中,只有extern声明...
似乎我不知道全局变量是如何工作的。非常感谢任何帮助!
答案 0 :(得分:3)
Globals可以声明多次,但必须定义一次。
“extern”关键字标记了作为声明的定义。
如何执行此操作的一般习惯用语如下:
// In a header file (declaration)
extern int myGlobal;
// In a source file (definition)
int myGlobal;
然后,在你想要引用全局的地方,你应该重复extern声明,或者包含已经有extern声明的头文件。
你应该不做的是将“int myGlobal”定义(没有“extern”)放入标题中。如果你这样做,那么包含该标题的每个文件都会尝试定义自己的myGlobal,并且在链接时最终会出现符号冲突。该定义应该只在一个源文件中。 extern声明可以出现在任意数量的文件或标题中。
特别是,你的两个错误发生了什么:
答案 1 :(得分:2)
诀窍是要知道每个.cpp文件都是一个编译单元 - 即编译的东西。每个人都是一个完整的个体,对彼此一无所知。它只是在链接阶段,它们汇集在一起。
现在,extern在编译的cpp文件中说“这个变量可以在其他地方找到”,编译器只是在链接器上放置一个引用提示来解决问题。
因此,当您将变量定义放在头文件中时,您可能会将该头包含在2个(或更多)cpp文件中。因此,每个cpp文件在编译时都认为它们具有真正的变量。然后链接器出现并看到太多。
将变量放入自己的cpp文件中(或放入主cpp文件中),并且只在头文件中放置extern引用。你应该可以使用乘法定义的符号。
答案 2 :(得分:0)
你说你有:
std::string errormsg;
int loglevel;
在libiup_dll.h
之外的任何#ifdefs
中的。如果多次(直接或间接)包含libiup_dll.h
,这是一个问题,并且可能是您的问题#2的原因。
我认为如果包含标题,这也可能是问题#1的原因 - 即使你可能不在其他地方使用它们,你也有标题引入的变量的定义。
这两个变量的定义通常需要在.c或.cpp文件中,而不是在标题中。对标题进行extern
声明可以在标题中找到。
答案 3 :(得分:0)
你说,
I implemented this by using
std::string errormsg;
int loglevel;
in libiup_dll.h (outside and #ifdefs, so it should be globally available),
and then putting
extern std::string errormsg;
extern int loglevel;
in my classes' .h files (outside the class, at the top of the files)
相反,我认为你应该在任意数量的头文件中使用extern
声明变量,然后定义变量而不用extern在一个 - 和 - 只有一个C或CPP文件。