共享库项目中的全局变量问题(C ++)

时间:2009-08-24 15:25:50

标签: c++ shared-libraries global-variables

我在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声明...

似乎我不知道全局变量是如何工作的。非常感谢任何帮助!

4 个答案:

答案 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声明可以出现在任意数量的文件或标题中。

特别是,你的两个错误发生了什么:

  • 在Linux下编译时,预处理器宏会删除定义全局变量的DLL头,因此你的全局变量有一个声明但没有定义,并且链接器会抱怨。
  • 在Windows下编译时,DLL标头包含在多个编译单元(源文件)中,因此全局变量有多个定义,并且链接器会抱怨。

答案 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文件。