静态变量存储在哪里(在C / C ++中)?

时间:2020-03-06 14:21:35  来源:igfitidea点击:

静态变量存储在可执行文件的哪个段(.BSS,.DATA等)中,以使它们不会发生名称冲突?
例如:

foo.c:                         bar.c:
static int foo = 1;            static int foo = 10;
void fooTest() {               void barTest() {
  static int bar = 2;            static int bar = 20;
  foo++;                         foo++;
  bar++;                         bar++;
  printf("%d,%d", foo, bar);     printf("%d, %d", foo, bar);
}                              }

如果我同时编译两个文件并将其链接到重复调用fooTest()和barTest的主文件,则printf语句将独立递增。这是有道理的,因为foo和bar变量是转换单元的本地变量。

但是在哪里分配存储空间?

明确地说,假设我们拥有一个可以以ELF格式输出文件的工具链。因此,我认为可执行文件中必须为这些静态变量保留一些空间。
出于讨论目的,假设我们使用GCC工具链。

解决方案

数据的存储位置将取决于实现。

但是,静态的含义是"内部链接"。因此,该符号在编译单元内部(foo.c,bar.c),并且不能在该编译单元外部引用。因此,不会有名称冲突。

这取决于我们使用的平台和编译器。一些编译器直接存储在代码段中。静态变量始终只能由当前翻译单元访问,并且不会导出名称,因此不会发生名称冲突的原因。

答案很可能取决于编译器,因此我们可能想要编辑问题(我的意思是,即使段的概念也不是ISO C或者ISO C ++所强制要求的)。例如,在Windows上,可执行文件不带有符号名。一个" foo"的偏移量为0x100,另一个可能为0x2B0,并且编译了来自两个转换单元的代码,知道它们" foo"的偏移量。

我不相信会发生冲突。在文件级别(外部函数)使用static会将变量标记为当前编译单元(文件)的本地变量。它在当前文件之外永远不可见,因此不必使用名称。

在函数内部使用静态变量有所不同,变量仅对函数可见,只是变量的值在对该函数的调用之间得以保留。

实际上,static根据其所在位置执行两项不同的操作。但是,在其他情况下,它会限制变量的可见性,以防止名称空间冲突,

话虽如此,我相信它会存储在倾向于初始化变量的DATA中。 BSS最初代表字节集-<something>,其中包含未初始化的变量。

它们都将被独立存储,但是,如果我们想让其他开发人员清楚,则可能需要将它们包装在命名空间中。

在"全局和静态"区域中:)

C ++中有几个内存区域

  • 免费商店
  • 全局和静态
  • const

请参阅此处以详细了解问题

如前所述,将静态变量存储在数据段或者代码段中。
我们可以确保不会在堆栈或者堆上分配它。
因为static关键字将变量的范围定义为文件或者函数,所以没有冲突的风险,如果发生冲突,会有编译器/链接器警告我们。
一个很好的例子

静态变量的去向取决于它们是否被初始化为0。 0个初始化的静态数据进入.BSS(以符号开头的块),非0初始化的数据进入.DATA

在编译单元中声明的数据将进入文件输出的.BSS或者.Data。 BSS中的初始化数据,DATA中未初始化的数据。

静态数据和全局数据之间的区别在于文件中包含符号信息。编译器倾向于包含符号信息,但仅这样标记全局信息。

链接器尊重此信息。静态变量的符号信息将被丢弃或者破坏,以便仍可以以某种方式(使用调试或者符号选项)引用静态变量。在两种情况下,编译器都不会受到影响,因为链接器首先解析本地引用。

实际上,变量是元组(存储,范围,类型,地址,值):

storage     :   where is it stored, for example data, stack, heap...
scope       :   who can see us, for example global, local...
type        :   what is our type, for example int, int*...
address     :   where are we located
value       :   what is our value

本地作用域可能意味着对翻译单元(源文件),功能或者块而言是本地的,具体取决于其定义的位置。为了使变量对多个功能可见,它肯定必须位于DATA或者BSS区域中(分别取决于其是否显式初始化)。然后将其范围限定为源文件中的所有功能或者所有功能。