指针存储什么地址?

What addresses do the pointer store?

我目前正在学习C中的指针。 我开始知道,指针是一个变量,它存储另一个变量的地址。 所以当我做类似的事情时,

#include <stdio.h>

int main()
{
    int x = 10;
    int *ptr;
    ptr = &x;
    printf("%d" ,ptr); 
   

上面给了我整数值的地址。
我的问题是,指针变量ptr 存储int 类型变量的地址。 根据我的 PC,int 占用 4 个字节,即 32 位。根据我的理解,每一位都有一个单独的内存地址。

那么地址指针将指向什么?它会指向第一位内存地址还是其他什么?请告诉我。

理解有误请指正

内存地址是一个字节的位置。 32 位位置是四字节边界上的位置。

因此内存地址 0x0000 等于第一个 32 位内存位置。地址 0x0004 将等于下一个四字节边界,或者换句话说,下一个 32 位位置。

那么就剩下big-endian and little-endian的问题了。

As per my understanding each bit has a separate memory address.

不,每个字节都有一个内存地址。您必须使用额外的偏移量来获取单个位。您不能使指针指向一个位。

So what is the address pointer will point to? Will it point to the first bits memory address or something else? Please let me know.

没有。它指向整个object。您不能说出对象中的哪个字节,因为这取决于字节顺序。

此外,当使用 -Wall -Wextra 编译时会给出警告。

warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’

您使用了错误的格式说明符来打印指针。 %d 用于 int。但是,您的指针的类型 int* 不是 int。如果要打印地址,请改用此地址:

printf("%p", (void*)ptr); 

最小寻址单位为字节。与int类型的对象占用多少字节无关,指向此类对象的指针指向该对象占用的内存范围的第一个字节。

来自 C 标准

3.5 1 bit

unit of data storage in the execution environment large enough to hold an object that may have one of two values

2 NOTE It need not be possible to express the address of each individual bit of an object.

3.6 1 byte addressable unit of data storage large enough to hold any member of the basic character set of the execution environment

注意这个调用

printf("%d" ,ptr); 

调用未定义的行为。

如果你想输出一个指针的值,你应该使用转换说明符p。例如

printf("%p\n" , ( void * )ptr); 

在像 x86 这样的系统上,每个单独的字节都有自己的地址。对于像 ints 或 doubles 这样的多字节对象,对象的地址是它的 first 字节的地址。在像 x86 这样的小端系统上,第一个字节是最低有效字节,而在像 Power 这样的大端系统上,第一个字节是最重要的字节:

int x = 0x01234567;

 A      A+1    A+2    A+3      big-endian
+––––––+––––––+––––––+––––––+
| 0x01 | 0x23 | 0x45 | 0x67 |
+––––––+––––––+––––––+––––––+
 A+3    A+2    A+1    A        little-endian

大多数架构都有对齐限制,因此多字节实体的地址必须是 2 或 4 的倍数。这就是为什么 struct 类型可能在成员之间有“填充”字节。

寻址和字节排序是底层架构的功能,而不是 C 语言的功能。在某些字寻址系统中,每个单独的字节 而不是 都有自己的地址,因此指向更小类型(如 char )的指针可能需要在字中包含一个偏移量。指针类型的表示可能会有所不同。

除非您在裸机上工作,否则您使用的地址值是虚拟地址,而不是物理地址。