变量名称如何存储在C中的内存中?

在C中,假设您有一个名为variable_name的变量。假设它位于0xaaaaaaaa,并且在该内存地址处,您具有整数123。换句话说,variable_name包含123。

我正在寻找有关短语“ variable_name位于0xaaaaaaaa”的说明。 编译器如何识别字符串“ variable_name”与该特定内存地址相关联? 字符串“ variable_name”是否存储在内存中的某个位置? 编译器在看到它时是否只是用0xaaaaaaaa代替0xaaaaaaaa,如果是这样,编译器是否不必使用内存来进行替换?

Tyler asked 2020-08-06T14:04:17Z
5个解决方案
73 votes

编译器运行后,变量名不再存在(除非出现特殊情况,例如共享库或调试符号中的导出全局变量)。 整个编译过程旨在采用源代码表示的那些符号名称和算法,并将其转换为本地机器指令。 因此,是的,如果您有一个全局movl,并且编译器和链接器决定将其放置在addl,则无论在代码中使用它的位置,都将通过该地址对其进行访问。

因此,回答您的字面问题:

编译器如何识别字符串“ variable_name”与该特定内存地址相关联?

工具链(编译器和链接器)协同工作,为变量分配存储位置。 跟踪所有引用是编译器的工作,稍后链接器将输入正确的地址。

字符串movl是否存储在内存中的某个位置?

仅在编译器运行时。

编译器在看到它时是否仅将movl替换为addl,如果是这样,它是否不必使用内存来进行替换?

是的,除了链接程序是分两步完成的工作以外,几乎所有事情都会发生。 是的,它使用内存,但是它是编译器的内存,而不是程序运行时的任何内容。

一个例子可以帮助您理解。 让我们尝试一下该程序:

int x = 12;

int main(void)
{
    return x;
}

很简单吧? 好。 让我们使用该程序,对其进行编译并查看反汇编:

$ cc -Wall -Werror -Wextra -O3    example.c   -o example
$ otool -tV example
example:
(__TEXT,__text) section
_main:
0000000100000f60    pushq   %rbp
0000000100000f61    movq    %rsp,%rbp
0000000100000f64    movl    0x00000096(%rip),%eax
0000000100000f6a    popq    %rbp
0000000100000f6b    ret

看到movl行吗? 它正在抓取全局变量(在这种情况下,是以指令指针相对的方式)。 没有更多提及addl

现在,让它变得更加复杂,并添加一个局部变量:

int x = 12;

int main(void)
{  
    volatile int y = 4;
    return x + y;
}

该程序的反汇编为:

(__TEXT,__text) section
_main:
0000000100000f60    pushq   %rbp
0000000100000f61    movq    %rsp,%rbp
0000000100000f64    movl    $0x00000004,0xfc(%rbp)
0000000100000f6b    movl    0x0000008f(%rip),%eax
0000000100000f71    addl    0xfc(%rbp),%eax
0000000100000f74    popq    %rbp
0000000100000f75    ret

现在有两个movl指令和addl指令。 您会看到第一个movl正在初始化y,它决定将在堆栈上(基本指针-4)。 然后下一个movl将全局x放入寄存器eax,然后addly加到该值。 但是正如您所看到的,文字xy字符串不再存在。 对于程序员来说,它们为您提供了便利,但是计算机在执行时当然并不关心它们。

Carl Norum answered 2020-08-06T14:05:22Z
9 votes

C编译器首先创建一个符号表,该表存储变量名与其在内存中的位置之间的关系。 如其他人所述,在编译时,它使用此表将变量的所有实例替换为特定的内存位置。 您可以在Wikipedia页面上找到更多信息。

MichaelThiessen answered 2020-08-06T14:05:44Z
6 votes

所有变量都由编译器替换。 首先,它们被引用替换,然后链接器放置地址而不是引用。

换一种说法。 编译器运行完后,变量名不再可用

junix answered 2020-08-06T14:06:09Z
6 votes

这就是所谓的实现细节。 虽然您所描述的是我曾经使用过的所有编译器的情况,但并非必须如此。 C编译器可以将每个变量放在哈希表中,然后在运行时(或类似的东西)查找它们,实际上,早期的JavaScript解释器正是这样做的(现在,他们进行Just-In-TIme编译会产生更多的原始结果。)

专门针对诸如VC ++,GCC和LLVM之类的常见编译器:编译器通常会将变量分配给内存中的某个位置。 全局或静态作用域的变量将获得一个固定的地址,该地址在程序运行时不会更改,而函数内的变量将获得一个堆栈地址,即相对于当前堆栈指针的地址,该地址每次函数被更改时都会更改 叫。 (这是一个过分的简化。)堆栈地址在函数返回后立即变为无效,但具有有效使用零开销的好处。

为变量分配地址后,就不再需要该变量的名称,因此将其丢弃。 根据名称的种类,名称可能会在预处理时(对于宏名),编译时(对于静态和局部变量/函数)和链接时间(对于全局变量/函数)被丢弃。 使其对其他程序可见,以便他们可以访问它),该名称通常保留在“符号表”中的某个位置,该表确实占用了少量的内存和磁盘空间。

Jonathan Grynspan answered 2020-08-06T14:06:40Z
4 votes

编译器在看到它时是否仅将variable_name替换为0xaaaaaaaa

是。

如果是这样,不是必须要使用内存才能进行替换吗?

是。 但是是编译器,在编译代码后,为什么还要关心内存?

vanza answered 2020-08-06T14:07:13Z
translate from https://stackoverflow.com:/questions/14612314/how-are-variable-names-stored-in-memory-in-c