【问题标题】:Where are global variables located in the activation record for C?C 的激活记录中的全局变量在哪里?
【发布时间】:2020-03-06 12:53:06
【问题描述】:

在 C 中,每个函数都有一个激活记录,该记录分配在堆栈帧上。局部变量分配在它们自己的函数的激活记录中。那么,全局变量是怎么回事呢?它们分配在哪里?

例如

#include <stdio.h>
    int a;

    void v()
    {a= 2;
    int b;
    b++;
    }

    main()
    {
    int f;
    printf("\n%d",a);
    v();
    }


-----Activation record----

-------------------
-------------------
activation record for main
-------------------
int f
-------------------
-------------------
activation record of v
--------------------
int a
--------------------
int b
--------------------
---------------

变量x根据激活记录逻辑存放在哪里?

【问题讨论】:

  • 全局变量不存储在“激活记录”(或“堆栈帧”)中。那是存储自动(或本地)变量的地方。但是,C 标准并没有规定变量的存储位置,只规定了它们应该如何工作。它没有提到术语“堆栈”、“堆”或“激活”。
  • 通常全局变量存储在所谓的数据段中。它是内存的一部分,在链接过程中映射到变量,并且在运行时不会更改。它在加载时分配在实际内存中。

标签: c global-variables activation-record


【解决方案1】:

在 C 中,每个函数都有一个激活记录,该记录分配在堆栈帧上。

不。但是,编译器通常是这样解决的。至少在您没有激活任何优化的情况下。

首先,C 标准根本没有提到堆栈。所以这个问题的答案将是关于它在实践中通常是如何解决的。

通常它们在数据段或bss段中。典型的布局如下所示:

Stack - Grows down towards the heap. Used for local variables.
-----
...
...
...
----
Heap - Grows up towards the stack. Used for dynamically allocated memory.
----
BSS - Uninitialized data. Used for uninitialized global and static variables.
----
Data - Initialized data. 
----
Text - Runnable code

【讨论】:

    【解决方案2】:

    在 C 中,每个函数都有一个激活记录,该记录分配在堆栈帧上。

    错误optimizing compiler 可能不会这样做(而 gcc -O3 -flto 不会,在 Linux / x86-64 上使用最近的 GCC)。它将inline 一些功能。一些本地人只保存在一些processor registers 中(所以没有内存位置)。阅读register allocation,例如在Dragon Book 或其他一些关于编译器的教科书中。请注意automatic variables。另请注意,您甚至不需要计算机来运行 C 程序(教 C 的一种好方法是让课堂上的游戏成为计算机;您可以用铅笔在纸上运行 C 程序)。

    call stack(保存调用帧或激活记录)上通常没有全局变量。它们可能位于data segment 中(并且可以完全优化)。

    C11 规范不需要任何调用堆栈。通过阅读n1570 进行检查。一些实现不使用任何调用堆栈(或激活记录)。请注意crt0 呼叫您的main

    阅读linkers and loaders 了解更多信息。另请阅读textbook about operating systems

    在 Linux 上,尝试 cat /proc/self/maps 以了解运行 cat 命令的 processvirtual address space;见proc(5)

    使用 Linux 查看gcc -O2 -fverbose-asm -S 生成的汇编代码。阅读invoking GCC

    另见this answer

    在 Linux 上,在 executableobject file 上使用 nm(1)readelf(1)objdump(1)ELF 格式)。

    【讨论】:

      猜你喜欢
      • 2011-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多