【问题标题】:Where do local variables get stored at compile time?局部变量在编译时存储在哪里?
【发布时间】:2016-04-21 20:04:27
【问题描述】:

也许我遗漏了一些明显的东西,但不是在运行时当包含变量的函数被调用时局部变量被放置在堆栈上。

因此,当编译器单步执行我们的源代码时,它会将函数的操作放在 .text 段中,但变量在编译时放在哪里,以便它们可以在运行时放入堆栈?谢谢

【问题讨论】:

  • 为什么不使用编译器选项来保存汇编代码,看看它是怎么做的?
  • 问:在你盖房子之前,你会在衣柜里放些什么? “变量”存储在“内存”中 - 在运行时加载程序之前不存在。 “编译”的是关于如何访问内存的说明。例如,局部变量“x”可能存储在寄存器“堆栈指针”的偏移量“2”处。汇编指令mov eax, [esp + 2] 会将“x”读入寄存器“a”(可能是为了进一步计算)。
  • 标准没有要求编译器使用堆栈或其他管理方式进行存储。
  • @Olaf:如果我有static char buf[10000];(隐式初始化为全零),那么目标文件或可执行文件中的任何位置可能都不会存储 10000 个字节。空间将在程序加载时分配。可执行文件只需要指定多少。
  • C 没有指定任何关于 stack.text 段 的内容。这些是给定编译器的工件。发布感兴趣的编译器。

标签: c++ c function compilation


【解决方案1】:

局部变量在编译时不会放在任何地方。

编译器生成的代码在运行时执行时会在堆栈上分配空间(通常;其他方案也是可能的)。编译器记录有关每个变量的信息(名称、类型、大小、相对于堆栈指针的偏移量等),并使用该信息生成创建、访问和最终释放变量的代码。

技术题外话:C 没有“本地”和“全局”变量,或者至少语言标准没有使用这些术语。一个对象有一个生命周期存储持续时间),它是当它存在时执行期间的时间跨度。或多或少与此无关,对象的名称有一个范围,它是名称可见的程序文本区域。在函数内声明的变量具有块作用域。默认情况下它具有自动存储持续时间(意味着它仅在包含块执行时存在),但如果它使用static 关键字定义,它具有静态存储持续时间 em> 或 如果它是在任何函数之外定义的。 “本地”static 变量的存储方式与“全局”变量相同,与“本地”自动变量的存储方式不同。

【讨论】:

  • 实际上,全局变量放置在某处。它们通常放在目标文件的 BSS 部分。当加载一个可执行文件时,BSS 被操作系统复制到进程的数据段中。
  • 这适用于带有文字初始化程序的全局变量。如果使用函数初始化,则 BSS 只包含一个默认值,并且生成的代码包含调用该函数并更新它的启动代码。
  • 不确定 C++,但 C 不要求堆栈或其他特定内存管理来放置 自动 变量。有些实现将它们分配在“正常”/非托管内存中。此外,像 static 这样的 local 变量永远不会放入普通堆栈中。
  • @Barmar:好的,我已经删除了对全局变量的引用。但是对于未初始化(隐式零初始化)全局(静态)变量,在目标文件或可执行文件中没有分配空间,只是表明需要多少零初始化静态空间。 (我认为。)
  • 对。虽然可以将具有恒定初始值的局部变量放入数据段,然后初始化局部变量的代码可以从那里执行 memcpy 到堆栈。
【解决方案2】:

关于你上面的comment

我想您是在问“问:编译器如何知道如何将源级构造(例如,int x)映射到运行时位置(例如 [esp + 2])。

是的,symbol tables 在编译器解析源代码并生成二进制目标文件时起着重要作用。

从上面的链接:

符号表是一种重要的数据结构,由 编译器以存储有关发生的信息 各种实体,如变量名、函数名、对象、 类,接口等。符号表用于分析 以及编译器的综合部分。

符号表可以用于以下目的,具体取决于 手语:

  • 将所有实体的名称以结构化形式存储在一个位置。

  • 验证变量是否已声明。

  • 要实现类型检查,通过验证源代码中的赋值和表达式在语义上是否正确。

  • 确定名称的范围(范围解析)。

但是生成和维护符号表只是编译器工作的一部分。以下是对整个过程的一些很好的概述:

【讨论】:

  • 指针必须存储在符号表中,对吗?否则编译器怎么知道增加指针的字节数?如果这个指针然后被转换成不同的指针,例如从 double * 到 int * ,这个信息会在符号表中更新吗?
  • 没有。上例中的“指针”是[esp + 2]。但实际的机器代码实现可能是anything,这取决于平台(本例中,x86)以及编译器如何选择实现局部变量(在本例中,作为当前堆栈指针的偏移量)。符号表不存储指针。要点是编译器的代码生成器查找符号表中的变量(以生成适当的代码)。
  • 但符号表不是也用于在运行时查找静态变量等的地址吗?
【解决方案3】:

C 和 C++ 都没有规定编译器在哪里存储本地(或全局)变量。

根据编译器的不同,局部变量可能存储在堆栈、CPU 寄存器或其他东西中,或者根本不存储。

【讨论】:

    【解决方案4】:

    局部变量在运行时处理,但全局变量在编译时处理,因为它们的范围是预定义的。全局变量存放在进程内存的数据段中,而局部变量存放在栈段中。

    可以用这段代码进行交叉验证:

    int a= 0;
    int main()
    {
         int b =0 ;
    }
    
    
    After compiling:
    
           .file   "test4.c"
            .globl  a
            .bss
            .align 4
            .type   a, @object
            .size   a, 4
    a:
            .zero   4
            .text
            .globl  main
            .type   main, @function
    ~                               
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-21
      • 2021-10-18
      • 2017-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多