存储在C中的指针地址在哪里?

Min*_*ock 4 c memory variables pointers memory-address

我正在学习C并且目前正在学习指针.我理解将一个字节的地址存储在内存中作为变量的原理,这使得从内存中获取字节并写入内存地址成为可能.

但是,我不明白指针的地址存储在何处.假设一个指针的值(内存中一个字节的地址)存储在内存中 - 程序如何知道指针的存储位置?难道不需要指针指针导致指针指针无穷无尽的指针......?


UPDATE

实际问题是:"编译器如何为变量分配内存地址".我发现这个问题指出了这个话题.

感谢所有回答的人.

Die*_*Epp 5

这是一个实现细节,但......

并非所有地址都存储在内存中.处理器还有寄存器,可用于存储地址.只有少数几个寄存器可以这种方式使用,可能是16或32,与你可以存储在内存中的数十亿字节相比.

寄存器中的变量

一些变量将存储在寄存器中.例如,如果需要快速添加一些数字,编译器可能会使用(例如,%eaxx86上的寄存器)来累积结果.如果启用了优化,则变量仅存在于寄存器中是很常见的.当然,在任何给定时间只有少数变量可以在寄存器中,因此大多数变量需要在某个时刻写入存储器.

如果由于没有足够的寄存器将变量保存到存储器,则称为"溢出".编译器非常努力地避免寄存器溢出.

int func()
{
    int x = 3;
    return x;
    // x will probably just be stored in %eax, instead of memory
}
Run Code Online (Sandbox Code Playgroud)

堆栈上的变量

通常,一个寄存器指向称为"堆栈"的特殊区域.因此,函数使用的指针可以存储在堆栈中,并且可以通过对堆栈指针执行指针运算来计算该指针的地址.堆栈指针没有地址,因为它是寄存器,寄存器没有地址.

void func()
{
    int x = 3; // address could be "stack pointer + 8" or something like that
}
Run Code Online (Sandbox Code Playgroud)

编译器选择堆栈的布局,为每个函数提供一个足够大的"堆栈帧"来容纳所有函数的变量.如果禁用优化,变量通常会在堆栈帧中获得自己的插槽.启用优化后,将重新使用,共享或优化插槽.

固定地址的变量

另一种替代方案是将数据存储在固定位置,例如"地址100".

// global variable... could be stored at a fixed location, such as address 100
int x = 3;

int get_x()
{
    return x; // returns the contents of address 100
}
Run Code Online (Sandbox Code Playgroud)

这实际上并不罕见.请记住,"地址100"不符合RAM,必然,它实际上是一个虚拟地址指的是你的程序的一部分虚拟地址空间.虚拟内存允许多个程序全部使用"地址100",并且该地址将对应于每个运行程序中的不同块物理内存.

绝对地址也可用于没有虚拟内存的系统,或者用于不使用虚拟内存的程序:引导加载程序,操作系统内核和嵌入式系统软件可以使用没有虚拟内存的固定地址.

绝对地址由编译器通过在机器代码中放置一个"空洞"来指定,称为重定位.

int get_x()
{
    return x; // returns the contents of address ???
              // Relocation: please put the address of "x" here
}
Run Code Online (Sandbox Code Playgroud)

然后链接器选择地址x,并将地址放在机器代码中get_x().

相对于程序计数器的变量

另一种替代方案是将数据存储在相对于正在执行的代码的位置.

// global variable... could be stored at address 100
int x = 3;

int get_x()
{
    // this instruction might appear at address 75
    return x; // returns the contents of this address + 25
}
Run Code Online (Sandbox Code Playgroud)

共享库几乎总是使用这种技术,它允许在程序的地址空间中可用的任何地址加载共享库.与程序不同,共享库无法选择其地址,因为另一个共享库可能选择相同的地址.程序也可以使用这种技术,这称为"位置无关的可执行文件".程序将独立于缺乏虚拟内存的系统,或者在具有虚拟内存的系统上提供额外的安全性,因为它使得编写shell代码变得更加困难.

就像使用绝对地址一样,编译器会在机器代码中放置一个"漏洞"并要求链接器填写它.

int get_x()
{
    return x; // return the contents of here + ???
              // Relocation: put the relative address of x here
}
Run Code Online (Sandbox Code Playgroud)