当前位置:  开发笔记 > 编程语言 > 正文

静态变量存储在C和C++中的哪个位置?

如何解决《静态变量存储在C和C++中的哪个位置?》经验,为你挑选了9个好方法。

在可执行文件的哪个段(.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的main,则printf语句将独立增加.有意义,因为foo和bar变量是翻译单元的本地变量.

但是存储分配在哪里?

需要明确的是,假设您有一个工具链可以输出ELF格式的文件.因此,我相信,有将一些空间,对于那些静态变量的可执行文件保留.
出于讨论目的,我们假设我们使用GCC工具链.



1> Don Neufeld..:

你的静力学去哪里取决于它们是否为零初始化.零初始化静态数据进入.BSS(由符号开始的块),非零初始化数据进入.DATA


通过"非0初始化"你可能意味着"初始化,但使用0以外的东西".因为在C/C++中没有"非初始化"的静态数据.默认情况下,静态的所有内容都是零初始化的.
@Don Neufeld:你的答案根本没有回答这个问题.我不明白为什么它被接受.因为'foo'和'bar'都是非0初始化的.问题是在.bss或.data中放置两个具有相同名称的静态/全局变量
@Andrey:无论如何,这就是我读这句话的方式.

2> 小智..:

当程序加载到内存中时,它被组织成不同的段.其中一个细分是DATA细分.数据段进一步细分为两部分:

初始化数据段:所有全局,静态和常量数据都存储在此处.
未初始化的数据段(BSS):所有未初始化的数据都存储在该段中.

这是一个解释这个概念的图表:

在此输入图像描述


这里是解释这些概念的非常好的链接:

http://www.inf.udec.cl/~leo/teoX.pdf



3> 小智..:

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

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区域(取决于它是否分别显式初始化).然后根据源文件中的所有函数或函数确定其范围.



4> Seb Rose..:

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

但是,静态的含义是"内部联系".因此,符号在编译单元内部(foo.c,bar.c),不能在编译单元外引用.所以,没有名称冲突.


ugasoft:函数外部的静态是连接修饰符,里面是存储修饰符,其中可以没有碰撞开始.

5> paxdiablo..:

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

在函数内部使用static是不同的 - 变量只对函数可见,它的值只是在对该函数的调用中保留.

实际上,静态根据它的位置做两件事.但是,在其他情况下,它会限制变量的可见性以防止命名空间冲突,

话虽如此,我相信它会存储在DATA中,而DATA往往具​​有初始化变量.BSS最初代表byte-set- ,它包含未初始化的变量.



6> ugasoft..:

在"全球和静态"领域:)

C++中有几个内存区域

免费商店

全球和静态

常量

请看这里详细解答您的问题



7> Ciro Santill..:

如何自己找到它 objdump -Sr

要真正了解发生了什么,您必须了解链接器重定位.如果你从未接触到这一点,请考虑先阅读这篇文章.

让我们自己分析一下Linux x86-64 ELF示例:

#include 

int f() {
    static int i = 1;
    i++;
    return i;
}

int main() {
    printf("%d\n", f());
    printf("%d\n", f());
    return 0;
}

编译:

gcc -ggdb -c main.c

用以下代码反编译代码:

objdump -Sr main.o

-S 用原始源混合反编译代码

-r 显示重定位信息

在反编译里面f我们看到:

 static int i = 1;
 i++;
4:  8b 05 00 00 00 00       mov    0x0(%rip),%eax        # a 
        6: R_X86_64_PC32    .data-0x4

.data-0x4说它将转到该.data段的第一个字节.

-0x4是因为我们正在使用RIP相对寻址,因此%rip在指令和中R_X86_64_PC32.

这是必需的,因为RIP指向以下指令,该指令从4个字节开始,之后00 00 00 00将重新定位.我在以下网址详细解释了这一点:https://stackoverflow.com/a/30515926/895245

然后,如果我们修改源i = 1并进行相同的分析,我们得出结论:

static int i = 0 继续 .bss

static int i = 1 继续 .data



8> 小智..:

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



9> itj..:

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

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

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

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有