首页 文章

当动态链接共享库中的全局变量和静态变量时会发生什么?

提问于
浏览
91

我试图理解当具有全局变量和静态变量的模块动态链接到应用程序时会发生什么 . 通过模块,我的意思是解决方案中的每个项目(我使用visual studio工作很多!) . 这些模块内置于* .lib或* .dll或* .exe本身 .

我知道应用程序的二进制文件包含数据段中所有单个转换单元(目标文件)的全局和静态数据(如果是const,则只读取数据段) .

  • 当此应用程序使用带有加载时动态链接的模块A时会发生什么?我假设DLL有一个全局和静态的部分 . 操作系统是否加载它们?如果是这样,他们在哪里被加载?

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

  • 如果我的应用程序中有两个使用A和B的模块,则是如下所述创建的A和B的全局变量的副本(如果它们是不同的进程)?

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

(请说明你的理由)

引自MSDN

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

here

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

谢谢 .

1 回答

  • 138

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

    无论:

    • 每个进程都有自己的地址空间,这意味着进程之间永远不会共享任何内存(除非您使用某些进程间通信库或扩展) .

    • 单一定义规则(ODR)仍然适用,这意味着您只能在链接时可以看到全局变量的一个定义(静态或动态链接) .

    所以,这里的关键问题是能见度 .

    在所有情况下, static 全局变量(或函数)从模块外部(dll / so或可执行文件)永远不可见 . C标准要求它们具有内部链接,这意味着它们在定义它们的转换单元(它成为目标文件)之外是不可见的 . 所以,这解决了这个问题 .

    它变得复杂的地方是你有 extern 个全局变量 . 在这里,Windows和类Unix系统完全不同 .

    对于Windows(.exe和.dll), extern 全局变量不是导出符号的一部分 . 换句话说,不同的模块无法识别其他模块中定义的全局变量 . 这意味着,如果您尝试创建应该使用DLL中定义的 extern 变量的可执行文件,则会出现链接器错误,因为这是不允许的 . 您需要提供一个对象文件(或静态库),其中包含该extern变量的定义,并将其与可执行文件和DLL静态链接,从而生成两个不同的全局变量(一个属于可执行文件,另一个属于DLL) ) .

    要在Windows中实际导出全局变量,必须使用类似于函数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;
    

    执行此操作时,全局变量将添加到导出符号列表中,并且可以像所有其他函数一样进行链接 .

    在类Unix环境(如Linux)的情况下,动态库名为"shared objects",扩展名为 .so ,导出所有 extern 全局变量(或函数) . 在这种情况下,如果从任何地方到共享对象文件进行加载时链接,则全局变量被共享,即,作为一个链接在一起 . 基本上,类似Unix的系统旨在使其与静态或动态库链接之间几乎没有区别 . 同样,ODR全面适用: extern 全局变量将在模块之间共享,这意味着它应该在所有加载的模块中只有一个定义 .

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

    当然,作为必要的最终说明: global variables should be avoided . 我相信你引用的文本(关于"unclear"的东西)正是指我刚才解释的平台特定的差异(动态库并没有真正由C标准定义,这是特定于平台的领域,这意味着它很多不太可靠/便携) .

相关问题