简体   繁体   English

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

[英]Where are addresses of pointers stored in C?

I'm learning C and currently learn about pointers. 我正在学习C并且目前正在学习指针。 I understand the principle of storing the address of a byte in memory as a variable, which makes it possible to get the byte from memory and write to the memory address. 我理解将一个字节的地址存储在内存中作为变量的原理,这使得从内存中获取字节并写入内存地址成为可能。

However, I don't understand where the address of a pointer is stored. 但是,我不明白指针的地址存储在何处。 Let's say the value of a pointer (the address of a byte in memory) is stored somewhere in memory - how can the program know where the pointer is stored? 假设一个指针的值(内存中一个字节的地址)存储在内存中 - 程序如何知道指针的存储位置? Wouldn't that need a pointer for a pointer resulting in endless pointers for pointers for pointers... ? 难道不需要指针指针导致指针指针无穷无尽的指针......?


UPDATE UPDATE

The actual question is: "How does the compiler assign memory addresses to variables". 实际问题是:“编译器如何为变量分配内存地址”。 And I found this question which points out this topic. 我发现这个问题指出了这个话题。

Thanks to everybody who's answered. 感谢所有回答的人。

This is an implementation detail, but... 这是一个实现细节,但......

Not all addresses are stored in memory. 并非所有地址都存储在内存中。 The processor also has registers, which can be used to store addresses. 处理器还有寄存器,可用于存储地址。 There are only a handful of registers which can be used this way, maybe 16 or 32, compared to the billions of bytes you can store in memory. 只有少数几个寄存器可以这种方式使用,可能是16或32,与你可以存储在内存中的数十亿字节相比。

Variables in registers 寄存器中的变量

Some variables will get stored in registers. 一些变量将存储在寄存器中。 If you need to quickly add up some numbers, for example, the compiler might use, eg, %eax (which is a register on x86) to accumulate the result. 例如,如果需要快速添加一些数字,编译器可能会使用例如%eax (x86上的寄存器)来累积结果。 If optimizations are enabled, it is quite common for variables to exist only in registers. 如果启用了优化,则变量仅存在于寄存器中是很常见的。 Of course, only a few variables can be in registers at any given time, so most variables will need to get written to memory at some point. 当然,在任何给定时间只有少数变量可以在寄存器中,因此大多数变量需要在某个时刻写入存储器。

If a variable is saved to memory because there aren't enough registers, it is called "spilling". 如果由于没有足够的寄存器将变量保存到存储器,则称为“溢出”。 Compilers work very hard to avoid register spilling. 编译器非常努力地避免寄存器溢出。

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

Variables on the stack 堆栈上的变量

Commonly, one register points to a special region called the "stack". 通常,一个寄存器指向称为“堆栈”的特殊区域。 So a pointer used by a function may be stored on the stack, and the address of that pointer can be calculated by doing pointer arithmetic on the stack pointer. 因此,函数使用的指针可以存储在堆栈中,并且可以通过对堆栈指针执行指针运算来计算该指针的地址。 The stack pointer doesn't have an address because it's a register, and registers don't have addresses. 堆栈指针没有地址,因为它是寄存器,寄存器没有地址。

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

The compiler chooses the layout of the stack, giving each function a "stack frame" large enough to hold all of that function's variables. 编译器选择堆栈的布局,为每个函数提供一个足够大的“堆栈帧”来容纳所有函数的变量。 If optimization is disabled, variables will usually each get their own slot in the stack frame. 如果禁用优化,变量通常会在堆栈帧中获得自己的插槽。 With optimization enabled, slots will be reused, shared, or optimized out altogether. 启用优化后,将重新使用,共享或优化插槽。

Variables at fixed addresses 固定地址的变量

Another alternative is to store data at a fixed location, eg, "address 100". 另一种替代方案是将数据存储在固定位置,例如“地址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
}

This is actually not uncommon. 这实际上并不罕见。 Remember, that "address 100" doesn't correspond to RAM, necessarily—it is actually a virtual address referring to part of your program's virtual address space . 请记住,“地址100”不符合RAM,必然,它实际上是指你的程序的虚拟地址空间的一部分的虚拟地址 Virtual memory allows multiple programs to all use "address 100", and that address will correspond to a different chunk of physical memory in each running program. 虚拟内存允许多个程序全部使用“地址100”,并且该地址将对应于每个运行程序中的不同块物理内存。

Absolute addresses can also be used on systems without virtual memory, or for programs which don't use virtual memory: bootloaders, operating system kernels, and software for embedded systems may use fixed addresses without virtual memory. 绝对地址也可用于没有虚拟内存的系统,或者用于不使用虚拟内存的程序:引导加载程序,操作系统内核和嵌入式系统软件可以使用没有虚拟内存的固定地址。

An absolute address is specified by the compiler by putting a "hole" in the machine code, called a relocation . 绝对地址由编译器通过在机器代码中放置一个“空洞”来指定,称为重定位

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

The linker then chooses the address for x , and places the address in the machine code for get_x() . 然后链接器选择x的地址,并将地址放在get_x()的机器代码中。

Variables relative to the program counter 相对于程序计数器的变量

Yet another alternative is to store data at a location relative to the code that's being executed. 另一种替代方案是将数据存储在相对于正在执行的代码的位置。

// 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
}

Shared libraries almost always use this technique, which allows the shared library to be loaded at whatever address is available in a program's address space. 共享库几乎总是使用这种技术,它允许在程序的地址空间中可用的任何地址加载共享库。 Unlike programs, shared libraries can't pick their address, because another shared library might pick the same address. 与程序不同,共享库无法选择其地址,因为另一个共享库可能选择相同的地址。 Programs can also use this technique, and this is called a "position-independent executable". 程序也可以使用这种技术,这称为“位置无关的可执行文件”。 Programs will be position-independent on systems which lack virtual memory, or to provide additional security on systems with virtual memory, since it makes it harder to write shell code. 程序将独立于缺乏虚拟内存的系统,或者在具有虚拟内存的系统上提供额外的安全性,因为它使得编写shell代码变得更加困难。

Just like with absolute addresses, the compiler will put a "hole" in the machine code and ask the linker to fill it in. 就像使用绝对地址一样,编译器会在机器代码中放置一个“漏洞”并要求链接器填写它。

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

The pointer is just a variable. 指针只是一个变量。 The only difference between this and, eg a long variable is that we know that what is stored in a pointer variable is a memory address instead of an integer. 这与...之间的唯一区别是,我们知道存储在指针变量中的内容是内存地址而不是整数。

Therefore, you can find the address of a pointer variable by the same way as you can find the address of any other variable. 因此,您可以通过与查找任何其他变量的地址相同的方式查找指针变量的地址。 If you store this address in some other variable, this one will also have an address, of course. 如果将此地址存储在其他变量中,当然这个地址也会有一个地址。

You confusion seems to originate from the fact that the pointer (ie a variable address) can in its turn be stored. 您的混淆似乎源于指针(即变量地址)可以依次存储的事实。 But it does not have to be stored anywhere (you only do it when you for some reason need this address). 但它不必存储在任何地方(只有当你出于某种原因需要这个地址时才会这样做)。 From the point of view of your program, any variable is more or less a named memory location. 从程序的角度来看,任何变量或多或少都是命名的内存位置。 So the "pointer to the variable" is a named memory location that contains the value that is supposed to "point" to another memory location, hence the name "pointer". 因此,“指向变量的指针”是一个命名的内存位置,它包含应该“指向”另一个内存位置的值,因此名称为“指针”。

A variable that is a pointer is still a variable, and acts like any other variable. 作为指针的变量仍然是变量,并且像任何其他变量一样起作用。 The compiler knows where the variable is located and how to access its value. 编译器知道变量的位置以及如何访问其值。 It is just that the value happens to be a memory address, that's all. 只是值恰好是一个内存地址,就是这样。

Let's say the value of a pointer (the address of a byte in memory) is stored somewhere in memory 假设指针的值(内存中字节的地址)存储在内存中的某处

The address of a byte that you allocated, say like this 您分配的字节的地址,如下所示

char ch = 'a';

is referenced by the compiler in the symbol table with the right offset. 由具有正确偏移量的符号表中的编译器引用。 At run time, the instructions generated by the compiler will use this offset for moving it to from the primary memory to a register for some operation on it. 在运行时,编译器生成的指令将使用此偏移量将其从主存储器移动到寄存器以对其进行某些操作。

A pointer, in the sense you're asking, is not stored anywhere, it's just a type when you refer to a variable's address, unless you explicitly create a pointer variable to store it like this 在你所问的意义上,指针不存储在任何地方,只是当你引用变量的地址时它只是一种类型, 除非你明确地创建一个指针变量来存储它就像这样

&ch;             // address of ch not stored anywhere
char *p = &ch;   // now the address of ch is stored in p

Thus there's no recursion concept here. 因此这里没有递归概念。

From the compilers perspective, whether u declare a pointer or a general variable is just a memory space.When you declare a variable a certain block of memory is allocated to the variable. 从编译器的角度来看,无论是声明指针还是通用变量,都只是一个内存空间。当您声明一个变量时,会为变量分配一定的内存块。

The variable can be any either a general variable or a pointer. 变量可以是常规变量或指针。 So ultimately we have a variables (even pointers are variables only) and they have a memory location. 所以最终我们有一个变量(甚至指针只是变量),它们有一个内存位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM