dynamic链接时共享库中的全局variables和静态variables会发生什么变化?
我想了解当全局variables和静态variables模块dynamic链接到应用程序时会发生什么。 通过模块,我的意思是每个项目在一个解决scheme(我工作了很多与Visual Studio!)。 这些模块是内置到* .lib或* .dll或* .exe本身。
我知道应用程序的二进制文件包含数据段中所有单个翻译单元(目标文件)的全局和静态数据(如果是const,则只读数据段)。
-
当这个应用程序使用带有加载时间dynamic链接的模块A时会发生什么? 我假设DLL有一个全局和静态的部分。 操作系统是否加载它们? 如果是这样,他们在哪里装载?
-
当应用程序使用带有运行时dynamic链接的模块B时会发生什么?
-
如果我的应用程序中有两个模块都使用A和B,那么是如下所述创build的A和B的全局variables的副本(如果它们是不同的进程)?
-
A和B是否可以访问应用程序全局variables?
(请说明你的理由)
从MSDN引用:
在DLL源代码文件中声明为全局的variables被编译器和链接器视为全局variables,但是加载给定DLL的每个进程都会获得该DLL全局variables的副本。 静态variables的范围仅限于声明静态variables的块。 因此,默认情况下,每个进程都有自己的DLL全局和静态variables的实例。
并从这里 :
在dynamic链接模块时,不清楚不同的库是否有自己的全局实例或者全局variables是否共享。
谢谢。
这是Windows和类Unix系统之间的一个非常有名的区别。
无论:
- 每个进程都有自己的地址空间,这意味着进程之间永远不会共享任何内存(除非使用某些进程间通信库或扩展)。
- 一个定义规则 (ODR)仍然适用,这意味着在链接时只能有一个全局variables定义(静态链接或dynamic链接)。
所以,这里的关键问题是真正的知名度 。
在所有情况下, static
全局variables(或函数)从模块外部(dll / so或者可执行文件)永远不可见。 C ++标准要求它们具有内部链接,这意味着它们在定义它们的翻译单元(它成为目标文件)之外是不可见的。 那么,这个问题就解决了。
当你有extern
全局variables时,它变得复杂。 在这里,Windows和类Unix系统是完全不同的。
对于Windows(.exe和.dll), extern
全局variables不是导出符号的一部分。 换句话说,不同的模块并不知道其他模块中定义的全局variables。 这意味着如果您尝试创build一个应该使用DLL中定义的extern
variables的可执行文件,则会出现链接错误,因为这是不允许的。 您需要提供一个带有该externvariables定义的对象文件(或静态库),并将其与可执行文件和DLL静态链接,从而生成两个不同的全局variables(一个属于可执行文件,一个属于DLL )。
要在Windows中实际导出全局variables,必须使用类似于函数export / import语法的语法,即:
#ifdef COMPILING_THE_DLL #define MY_DLL_EXPORT extern "C" __declspec(dllexport) #else #define MY_DLL_EXPORT extern "C" __declspec(dllimport) #endif MY_DLL_EXPORT int my_global;
当你这样做,全局variables被添加到导出的符号列表,并可以像所有其他function一样链接。
在类Unix环境(如Linux)中,dynamic库(称为“共享对象”,扩展名为.so
导出所有extern
全局variables(或函数)。 在这种情况下,如果你从任何地方加载时间链接到一个共享对象文件,那么全局variables是共享的,即作为一个整体链接在一起。 基本上,类Unix系统的devise使得与静态或dynamic库链接几乎没有区别。 同样,ODR全面应用:一个extern
全局variables将被跨模块共享,这意味着它应该只有一个跨所有加载模块的定义。
最后,在这两种情况下,对于Windows或类Unix系统,可以使用LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
或dlopen()
/ dlsym()
/ dlclose()
。 在这种情况下,您必须手动获取您希望使用的每个符号的指针,并且包含您希望使用的全局variables。 对于全局variables,只要全局variables是导出符号列表的一部分(按照前面段落的规则dlsym()
就可以像使用函数一样使用GetProcAddress()
或dlsym()
)。
当然,作为一个必要的最后说明: 应该避免全局variables 。 我相信你所引用的文本(关于事物“不清楚”)恰恰是指我刚刚解释的特定于平台的差异(dynamic库不是真正由C ++标准定义的,这是特定于平台的领域,意味着它是不太可靠/便携式)。