Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当共享库动态链接时,它的全局变量和静态变量会发生什么变化?_C++_Linker_Global Variables_Global_Dynamic Linking - Fatal编程技术网

C++ 当共享库动态链接时,它的全局变量和静态变量会发生什么变化?

C++ 当共享库动态链接时,它的全局变量和静态变量会发生什么变化?,c++,linker,global-variables,global,dynamic-linking,C++,Linker,Global Variables,Global,Dynamic Linking,我试图理解当带有全局变量和静态变量的模块动态链接到应用程序时会发生什么。 说到模块,我指的是解决方案中的每个项目(我经常使用VisualStudio!)。这些模块要么内置在*.lib或*.dll中,要么内置在*.exe中 我知道应用程序的二进制文件包含数据段中所有单个翻译单元(对象文件)的全局和静态数据(如果为常量,则为只读数据段) 当此应用程序使用具有加载时动态链接的模块a时会发生什么情况?我假设DLL有一个用于全局和静态的部分。操作系统是否加载它们?如果是这样,它们将装载到哪里 当应用程序

我试图理解当带有全局变量和静态变量的模块动态链接到应用程序时会发生什么。 说到模块,我指的是解决方案中的每个项目(我经常使用VisualStudio!)。这些模块要么内置在*.lib或*.dll中,要么内置在*.exe中

我知道应用程序的二进制文件包含数据段中所有单个翻译单元(对象文件)的全局和静态数据(如果为常量,则为只读数据段)

  • 当此应用程序使用具有加载时动态链接的模块a时会发生什么情况?我假设DLL有一个用于全局和静态的部分。操作系统是否加载它们?如果是这样,它们将装载到哪里

  • 当应用程序使用带有运行时动态链接的模块B时会发生什么

  • 如果我的应用程序中有两个模块都使用A和B,那么A和B的全局文件的副本是否按以下所述创建(如果它们是不同的进程)

  • DLL A和B是否可以访问全局应用程序

(请说明你的理由)

引述自:

编译器和链接器将DLL源代码文件中声明为全局的变量视为全局变量,但加载给定DLL的每个进程都会获得该DLL全局变量的自己副本。静态变量的范围仅限于声明静态变量的块。因此,默认情况下,每个进程都有自己的DLL全局变量和静态变量实例

和来自:

动态链接模块时,可能不清楚不同的库是否有自己的全局实例,或者全局是否共享


谢谢。

这是Windows和类Unix系统之间非常著名的区别

不管怎样:

  • 每个进程都有自己的地址空间,这意味着进程之间永远不会共享任何内存(除非您使用一些进程间通信库或扩展)
  • 一个定义规则(ODR)仍然适用,这意味着您在链接时只能看到全局变量的一个定义(静态或动态链接)
因此,这里的关键问题是可见性

在所有情况下,
静态
全局变量(或函数)永远不会从模块(dll/so或可执行文件)外部可见。C++标准要求这些具有内部链接,这意味着它们在翻译单元(成为对象文件)之外不可见,在它们中定义了翻译单元。这就解决了这个问题

当您有
extern
全局变量时,它变得复杂起来。在这里,Windows和类Unix系统完全不同

在Windows(.exe和.dll)的情况下,
extern
全局变量不是导出符号的一部分。换句话说,不同的模块完全不知道在其他模块中定义的全局变量。这意味着,如果您尝试创建一个应使用DLL中定义的
extern
变量的可执行文件,则会出现链接器错误,因为这是不允许的。您需要提供一个包含该外部变量定义的对象文件(或静态库),并将其与可执行文件和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)中,动态库称为“共享对象”,扩展名为
。因此
导出所有
extern
全局变量(或函数)。在这种情况下,如果确实从任何位置加载时间链接到共享对象文件,则全局变量是共享的,即作为一个变量链接在一起。基本上,类Unix系统的设计目的是使与静态库或动态库的链接几乎没有区别。同样,ODR适用于所有模块:一个
extern
全局变量将在模块之间共享,这意味着它在所有加载的模块中应该只有一个定义

最后,在这两种情况下,对于Windows或类似Unix的系统,都可以执行动态库的运行时链接,即使用
LoadLibrary()
/
GetProcAddress()
/
FreeLibrary()
dlopen()
/
dlsym()
/
dlclose()
。在这种情况下,您必须手动获取指向您希望使用的每个符号的指针,其中包括您希望使用的全局变量。对于全局变量,可以使用与函数相同的
GetProcAddress()
dlsym()
,前提是全局变量是导出符号列表的一部分(根据前面段落的规则)


当然,作为必要的最后一点:应该避免使用全局变量。我相信你所引用的文本(关于“不清楚”)正是指我刚才解释的平台特定差异(动态库不是真正由C++标准定义的,这是平台特定的领域,这意味着它更不可靠/可移植)。.

这是Windows和类Unix系统之间非常著名的区别

不管怎样:

  • 每个进程都有自己的地址空间,这意味着进程之间永远不会共享任何内存(除非您使用一些进程间通信库或扩展)
  • 一个定义规则(ODR)仍然适用,这意味着您只能有一个定义
    segfault at xxxxxx ip xxxxxx sp xxxxxxx error 15 in a.out