共享库不是 C 概念。不同操作系统和计算平台(如果存在)的共享库实现在形式和行为上表现出差异。
尽管如此,是的,我所知道的所有共享库实现都支持变量,从 C 的角度来看,静态存储持续时间和外部链接,我认为这就是您所说的“全局”的意思。由于您似乎使用的是 Linux,因此您的共享库将具有 ELF 风格。在这种情况下,动态链接共享库的每个进程都将获得自己的此类变量的副本。
您描述的大变量地址没有特别的后果。 ELF共享库不必加载到任何特定地址,事实上Linux实现了ASLR,它主动使库加载地址发生变化。您的共享库或多或少可以加载到系统 64 位虚拟地址空间中的任何位置,因此您实际上无法理解变量地址的数值很大这一事实。
至于您描述的错误,我倾向于认为它是由错误代码引起的,而不是(直接)由共享库的参与引起的。根据您的描述,我怀疑您最终得到了多个同名变量,所有变量都具有外部链接。这是静态链接的错误,但在这种情况下,编译器可以(默认情况下 GCC 会)合并重复的变量而不是拒绝代码。
另一方面,使用 ELF,可以在链接到同一进程的多个共享对象中定义相同的符号,并且可以从整个进程中的不同点引用不同的定义。由于共享库是与主程序分开编译的,因此编译器没有机会合并符号,即使可以,也并不明显应该这样做。但是给定符号的多个声明是可能性 not a 必要性。如果发生这种情况,可能是因为您的标头错误地声明了变量。
程序中任何给定变量可能有多个声明,但必须只有一个定义。声明通常来自头文件,它们应该如下所示:
extern int foo;
The extern
is 强制的如果要在多个源文件中使用标头,并且缺少初始化程序,则声明不能被解释为定义。然后应该在一个源文件中定义该变量,如下所示:
int foo = 0;
初始值设定项的存在表明该声明也是一个定义。如果省略初始化器,它可能仍然是一个定义,只要extern
不包括限定符,但如果您不想了解所有细节,那么只提供一个初始化程序是安全的。
如果有定义,就会出现您所描述的问题foo
在多个共享对象中。例如,如果头文件包含以下任一形式的声明,就会发生这种情况:
bad.h
int foo; /* WRONG - without extern, this is a tentative definition */
extern int bar = 0; /* WRONG - because of the initializer, this is a definition */