我在 M1 macbook air 上使用 Apple clang 版本 14.0.0 (clang-1400.0.29.202) 运行它。
#include<stdio.h>
int main()
{
unsigned int a = 'A';
unsigned int i = -1;
unsigned int *ptr = &i;
printf("%p\n",&ptr);
printf("%p\n",ptr);
printf("--------\n");
char *p = (char *)ptr;
printf("%p\n",&i);
printf("%p\n",&a);
printf("--------\n");
printf("%p\n",p);
printf("%p\n",p + 1);
printf("%p\n",p + 2);
printf("%p\n",p + 3);
printf("%p\n",p + 4);
printf("%p\n",p + 5);
printf("%p\n",p + 6);
printf("%p\n",p + 7);
printf("--------\n");
printf("%u\n",*p);
printf("%u\n",*(p + 1));
printf("%u\n",*(p + 2));
printf("%u\n",*(p + 3));
printf("%c %u\n",*(p + 4),*(p + 4));
printf("%c %u\n",*(p + 5),*(p + 5));
printf("%c %u\n",*(p + 6),*(p + 6));
printf("%c %u\n",*(p + 7),*(p + 7));
}
我试图了解 64 位平台的内存布局。类型 int(unsigned int) 的大小为 4 个字节,如地址所示,变量
a
和 i
的地址之间的差异是 4。而 i
的值是 2^32-1,这表明它使用 exact 4 个字节表示一个 int 数字。 char 类型的大小为 1byte,所以它的指针值加 1 时也加 1。
对我来说奇怪的是,每次字符指针
p
递增时,p
指向的值与i
相同,直到p
移动“进入”变量a
。当在p + 4
行时,它的值等于'A'
.
按我的理解,64bits 是指每个内存位置有64bits 可以存储,但是int 类型只需要32 位,所以每个int 变量都完全存储在一个内存位置?但是指针值和地址值似乎不支持这个。那么这是否意味着每个内存位置都有一个字节?(我不知道从哪里可以弄清楚,所以这可能是一个错误的猜想)。
第二,当指针
printf
的值是“内部”变量p
时,为什么函数i
打印2^32-1,这通常是正确的还是只是一个UB?但是对于a = 'A'
,printf
似乎表现不同,当A 65
和p + 4
在其余情况下打印 0
。
那么 64 位平台的布局是怎样的?它的内存是如何工作的? C中的地址值是什么意思?
或者有什么书籍、手册或文档可以让我找到一些关于这个的解释吗?
更新:我忘了添加自己的输出
0x16da0b4f0
0x16da0b4f8
--------
0x16da0b4f8
0x16da0b4fc
--------
0x16da0b4f8
0x16da0b4f9
0x16da0b4fa
0x16da0b4fb
0x16da0b4fc
0x16da0b4fd
0x16da0b4fe
0x16da0b4ff
--------
4294967295
4294967295
4294967295
4294967295
A 65
0
0
0
您通常无法通过编写代码并在(单个)系统上运行来了解“64 位平台中的内存布局”。您可能会了解有关特定系统的内容,但通常 C 标准不会指定代码中的变量如何放置在内存中。其中很多留给了实施。换句话说,不同的(64 位)系统、不同的编译器、不同的编译器选项等可能会发生变化。对结论如此谨慎......
对于这个问题:
对我来说奇怪的是,每次 char 指针 p 递增时,p 指向的值与 i 相同,直到 p 移动“进入”变量 a。当在 p + 4 行时,它的值等于'A'。
假设:
您的系统使用 4 个字节
int
您的系统对有符号整数使用 2 的补码编码
您的系统使用signed
char
type
上面的前两个意味着
i
在内存中的位置为 FF FF FF FF
对于整数值 -1
当您设置
char
指针p
指向i
时,它将指向保存第一个FF
的内存,并且它只会访问那个单一的FF
。由于上面的数字 3 也是整数值 -1.
您使用
unsigned int
将该值打印为 %u
。这涉及从一种整数类型到另一种整数类型的转换。 C 标准描述了这是如何完成的。有关详细信息,请参阅C - 将 ~0 转换为无符号长
当你打印下一个字符时,即
*(p + 1)
你读到第二个 FF
(并且只有第二个)也是 -1(由于第 3 点)并且同样的事情再次发生。
和
*(p + 2)
和*(p + 3)
一样。
为了好玩,你可以试试这个代码
unsigned int i = -1;
char *p = (char *)&i;
printf("Using char-pointer: %u\n",*p);
printf("Using char-pointer: %u\n",*(p + 1));
printf("Using char-pointer: %u\n",*(p + 2));
printf("Using char-pointer: %u\n",*(p + 3));
unsigned char *pu = (unsigned char *)&i;
printf("Using unsigned char-pointer: %u\n",*pu);
printf("Using unsigned char-pointer: %u\n",*(pu + 1));
printf("Using unsigned char-pointer: %u\n",*(pu + 2));
printf("Using unsigned char-pointer: %u\n",*(pu + 3));
查看有符号和无符号字符类型之间的区别。
输出:
Using char-pointer: 4294967295
Using char-pointer: 4294967295
Using char-pointer: 4294967295
Using char-pointer: 4294967295
Using unsigned char-pointer: 255
Using unsigned char-pointer: 255
Using unsigned char-pointer: 255
Using unsigned char-pointer: 255
对于通过从变量中读取字节来访问的值
a
它是一样的:
unsigned int a = 'A'; ---> memory: 41 00 00 00
所以你第一次阅读
41
(或'A'
),其余的你阅读00