我想知道当全局和静态变量的模块动态链接到一个应用程序会发生什么。 通过模块,我的意思是在溶液中每个项目(我工作了很多与Visual Studio!)。 这些模块要么内置*的.lib或* .DLL或* .EXE本身。
据我所知,一个应用程序的二进制包含所有数据段的各个翻译单元(目标文件)的全局和静态数据(如果const的只读数据段)。
当该应用程序使用一个模块A带负载时动态链接,会发生什么? 我假设DLL有其全局和静态的部分。 是否在操作系统加载它们? 如果是这样,他们究竟是怎么装到?
当应用程序使用与运行时动态链接一个模块B会发生什么?
如果我有我的应用程序两个模块都使用A和B,如下文提到的(如果他们是不同的程序)中创建A和B的全局变量的副本?
不要的DLL A和B可以访问应用程序的全局变量?
(请说出你的理由,以及)
从引用MSDN :
被声明为在DLL源代码文件的全局变量被视为由编译器和连接器的全局变量,但每加载一个给定的DLL进程都有自己的该DLL的全局变量的副本。 静态变量的范围仅限于在其中静态变量声明的块。 其结果是,每个进程都有自己默认的DLL全局和静态变量的实例。
从这里 :
当动态链接模块,也可以是不同的不清楚是否库有自己的全局的实例或全局是否是共享的。
谢谢。
这是Windows和Unix类系统之间一个非常著名的差异。
无论:
- 每个进程都有自己的地址空间,这意味着永远不会在进程间共享的任何内存(除非你使用一些进程间通信库或扩展)。
- 在一个定义规则 (ODR)仍然适用,这意味着你只能有全局变量在链接时(静态或动态链接)可见的一个定义。
所以,这里的关键问题是真是知名度 。
在所有情况下, static
全局变量(或函数)是从模块(DLL / SO或可执行文件)外,绝对不会看到。 C ++标准要求这些具有内部链接的,这意味着它们不是翻译单元(它成为一个对象文件),其中它们被定义外部可见。 因此,就解决该问题。
它变得复杂是当你拥有extern
全局变量。 在这里,Windows和Unix类系统是完全不同的。
在Windows(.exe和.dll)的情况下, extern
全局变量而不是导出符号的一部分。 换句话说,不同的模块绝不知道在其他模块中定义的全局变量。 这意味着你会得到链接错误,如果你尝试,例如,创建一个应该使用一个可执行extern
在DLL中定义的变量,因为这是不允许的。 您需要提供与外部变量的定义目标文件(或静态库),并与可执行文件和DLL 都静态链接它,从而导致两种不同的全局变量(一个属于可执行文件,一个属于DLL )。
要真正导出一个全局变量在Windows中,你必须使用类似功能导出/导入语法,即语法:
#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;
当你这样做,全局变量被添加到导出的符号列表,可以像其他所有的功能链接。
在类Unix的环境(如Linux)的情况下,动态库,被称为“共享对象”扩展.so
导出所有extern
全局变量(或功能)。 在这种情况下,如果你做的加载时间从任何地方共享对象文件链接,然后全局变量是共享的,即连接在一起作为一个。 基本上,类Unix系统的设计让这个有一个静态或动态链接库之间实际上没有任何区别。 再次,ODR适用全线:一个extern
全局变量将跨模块共享的,这意味着它只能有一个定义,所有的模块加载。
最后,在两种情况下,Windows或Unix类系统中,你可以做的运行时链接的动态库的,也就是说,用LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
或dlopen()
/ dlsym()
/ dlclose()
在这种情况下,你必须手动得到一个指向每一个你希望使用的符号,这包括您希望使用的全局变量。 对于全局变量,你可以使用GetProcAddress()
或dlsym()
一样的,你对功能做,前提是全局变量导出的符号列表(由段落中的规则)的一部分。
,当然,作为一个必要的最终注: 全局变量应该尽量避免 。 而且我相信,文本您引用(约事情都是“不清楚”)恰好指的是我刚才解释特定于平台的差异(动态库是不是真的由C ++标准定义,这是特定于平台的领土,这意味着它要少得多可靠/便携式)。
文章来源: What happens to global and static variables in a shared library when it is dynamically linked?