6

考虑下面非常简单的代码:

#include <stdio.h>
#include <stdlib.h>
int main() {

    int* a = (int*) malloc(10 * sizeof(int));
    printf("a = %p, a+1 = %p", a, a+1);
    return 0;
}

输出是这样的:

a = 0x127f190, a+1 = 0x127f194

由于 an 的大小int是 4 个字节,我从上面的结果中假设指针值是我的 RAM 内存上一个字节的索引。因此a+1实际上增加了aby sizeof(int) = 4(bytes) 的值。那是对的吗?

如果是,那么为什么我要从我的程序中获取 32 位内存地址?这台机器是 64 位的,运行 64 位版本的 Ubuntu。如何让程序打印完整的 64 位地址?我必须用特殊标志编译它吗?

4

5 回答 5

7

你的指针是正确的。内存传统上是按字节组织和寻址的,指针指向它们所指向的任何内容的第一个字节(编辑:它们不必这样做,但在通常的平台和编译器上它们会这样做)。

您没有看到“64 位”指针仅仅是因为输出去除了前导 0 :-) 如果您执行 sizeof(a),您可能会在 32 位系统上获得“4”,而“8”在 64 位系统上。

于 2012-08-26T18:30:57.303 回答
4

我的 RAM 内存中一个字节的索引

这对于大多数目的来说已经足够接近了,但并不完全准确。它是进程地址空间中一个字节的索引。虚拟地址与物理 RAM 没有直接关系,有一种叫做“虚拟内存管理器”的东西,它负责跟踪每个进程中的哪些虚拟地址引用了哪些物理 RAM(以及 RAM 以外的东西)。

通常你可以忘记这一点,而只是将虚拟地址空间视为 RAM(或将其视为抽象的“内存”)。但是不同进程中的同一个虚拟地址可以引用不同的物理内存,或者不同进程中不同的虚拟地址可以引用同一个内存。或者同一进程中的相同虚拟地址可能在不同时间引用不同的物理内存,如果操作系统注意到该页面有一段时间没有使用,则将其交换到磁盘,然后在再次使用时将其返回内存。因此,它并不是 RAM 本身的真正“地址”,它只是操作系统为您的进程提供的地址,用于引用一些 RAM。

于 2012-08-26T19:08:45.313 回答
1

您看到增加 4 的原因是因为您正在为整数分配内存,整数长度固定为 4 个字节(在 Intel Linux gcc 中)——无论您编译的是 32 位还是 64 位代码。如前所述,您获得的指针指的是虚拟内存地址,而不是物理内存。

如果将 int 更改为 long,您将看到 32 位代码增加 4 个字节,而 64 位代码增加 8 个字节。

此外,如果您查看sizeof(void *)它会告诉您指针是 32 位还是 64 位。如果您的指针是 64 位的,那么您将得到 64 位的指针,并使用 %p 打印。

我编辑了您的程序以在我的 Ubuntu 副本上运行,并添加:

printf("Size of pointer = %d\n", (int)sizeof(void *));

这是输出:

a = 0x2067010, a+1 = 0x2067014
Size of pointer = 8

所以指针确实是64位的。

于 2012-08-27T10:12:00.097 回答
0

当您编写 时int* a = (int*) malloc(10 * sizeof(int));,您正在为一个包含十个元素的数组分配内存。这相当于int a[10];并且 a = 0x127f190是第一个元素的地址a[0]

于 2012-08-26T18:29:35.407 回答
0

对不起,没有给你一个确切的答案。但它来了:

寻找Pointer Arithmetic,你会找到你要找的一切。

即使您的系统运行 x64,大多数编译器都默认使用 x86,除非您特别声明为 x64 编译。因此,在编译器文档中搜索 x64 标志和相关选项。

于 2012-08-26T18:30:47.127 回答