C指针和物理地址

我刚刚开始C.我已阅读各种书籍/教程中的指针,我理解基础知识。 但有一点我没有看到解释的是数字是多少。

例如:

int main(){ int anumber = 10; int *apointer; apointer = &anumber; printf("%i", &apointer); } 

可能会返回一个像4231168这样的数字。这个数字代表什么? 它是RAM中的一些存储名称吗?

很多PC程序员一如既往地回复。 这是来自通用编程观点的回复。

在进行任何forms的硬件相关编程时,您会对地址的实际数值感兴趣。 例如,您可以通过以下方式访问计算机中的硬件寄存器:

 #define MY_REGISTER (*(volatile unsigned char*)0x1234) 

此代码假定您知道位于地址0x1234的特定硬件寄存器。 计算机中的所有地址都是传统的/为了方便起见以hex格式表示。

在此示例中,地址长度为16位,这意味着所使用的计算机上的地址总线为16位宽。 计算机中的每个存储单元都有一个地址。 因此,在16位地址总线上,最多可以有2 ^ 16 = 65536个可寻址存储单元。 例如,在PC上,地址通常为32位长,为您提供429亿个可寻址存储单元,即4.29千兆字节。

要详细解释这个宏:

  • 0x1234是寄存器/存储器位置的地址。
  • 我们需要通过指针访问这个内存位置,因此我们将整数常量0x1234转换为unsigned char指针=指向一个字节的指针。
  • 这假设我们感兴趣的寄存器大1字节。 如果它是两个字节大,我们可能会使用unsigned short代替。
  • 硬件寄存器可以随时更新(它们的内容是“易失性的”),因此不允许程序对存储在其中的内容进行任何假设/优化。 程序必须在代码中使用寄存器时从寄存器中读取值。 要强制执行此行为,我们使用volatile关键字。
  • 最后,我们想要访问寄存器就像它是一个普通变量一样。 因此添加*,以获取指针的内容。

现在程序可以访问特定的内存位置:

 MY_REGISTER = 1; unsigned char var = MY_REGISTER; 

例如,像这样的代码在嵌入式应用程序的任何地方都使用。

(但正如在其他回复中已经提到的那样,你不能在现代PC中做这样的事情,因为他们正在使用一种叫做虚拟寻址的东西,如果你尝试它就会给你一记耳光。)

它是指针所指向的内存的地址或位置。 但是,最好将此视为一个不透明的数量 – 您永远不会对指针的实际值感兴趣,只会对它所引用的值感兴趣。

地址与物理内存的关系如何是系统提供的服务,并且实际上是跨系统变化的。

这是anumber变量的虚拟地址。 每个程序都有自己的内存空间,并且内存空间映射到物理内存。 由处理器完成的映射id和用于该处理的服务数据由操作系统维护。 所以你的程序永远不知道它在物理内存中的位置。

它是存储变量的内存1位置的地址。 你不应该关心确切的值,你应该知道不同的变量有不同的地址,“连续的内存”(例如数组)有连续的地址,…

顺便说一下,要打印存储在指针中的地址,您应该使用printf%p说明符。


  1. 请注意,我没有说“RAM”,因为在大多数现代操作系统中,您的进程看到的“内存”是虚拟内存,即操作系统管理的实际RAM的抽象。

很多人告诉你,指针的数值会指定它的地址。 这是实现可以实现的一种方式,但是非常重要,C标准对指针的评价是:

  • 当使用C编程语言操作时,nil指针始终为数值0。 但是,包含指针的实际内存可以具有任何值,只要这个特殊的,依赖于体系结构的值始终处理为nil,并且实现需要注意该值被C源代码视为0。 这一点很重要,因为在使用低级别内存调试器进行检查时,0指针在某些体系结构上可能显示为不同的值。
  • 没有任何要求指针的值与实际地址有任何关系。 它们也可以是抽象标识符,由LUT或类似物解析。
  • 如果指针指向一个数组,则指针算术的规则必须保持,即int array[128]; int a, b; a = (int)&array[120]; b = (int)&array[100]; a - b == 20 ; array + (ab) == &array[20]; &array[120] == (int*)a int array[128]; int a, b; a = (int)&array[120]; b = (int)&array[100]; a - b == 20 ; array + (ab) == &array[20]; &array[120] == (int*)a
  • 指向不同对象的指针之间的指针算法未定义,并导致未定义的行为。
  • 指向整数的映射指针必须是可逆的,即如果数字对应于有效指针,则转换为此指针必须有效。 但是,对指向不同对象的指针的数字表示的(指针)算法是未定义的。

是的,确切地说 – 它是内存中apointer数据的地址。 诸如anumber和apointer之类的局部变量将在程序的堆栈中分配,因此它将引用堆栈中main()函数框架中的地址。

如果你已经使用malloc()分配内存,那么它将引用程序堆空间中的位置。 如果它是固定字符串,则可以引用程序数据中的位置或rodata(只读数据)段。

在这种情况下,apointer表示指针变量apointer的RAM存储器中的地址

apointer是变量数的“地址”。 理论上,它可能是存储数值的RAM中的实际物理位置,但实际上(在大多数操作系统中)它可能是虚拟存储器中的一个位置。 结果虽然如此。

它是一个内存地址,最有可能是程序堆栈中的当前位置。 与大卫的评论相反,有时你会计算指针偏移量,但这只是你正在处理的某种数组。

它是指针的地址。

“anumber”在RAM中占用一些空间,此位置的数据包含数字10。

“apointer”也会在RAM中占用一些空间,此位置的数据包含RAM中“anumber”的位置。

所以,假设你有32个字节的ram,地址为0..31

在例如位置16,你有4个字节,“anumber”值10

在例如位置20,你有4个字节,“apointer”值16,“anumber”在RAM中的位置。

你打印的是20,apointer在RAM中的位置。

请注意,这不是直接在RAM中,而是在映射到RAM的虚拟地址空间中。 为了理解指针,您可以完全忽略虚拟地址空间。

它不是打印的变量数字的地址,而是打印的指针的地址。仔细查看。它只是“apointer”,然后我们就会看到anumber变量的地址。