如何理解 64 位平台上 C 中的内存布局和地址值的含义

问题描述 投票:0回答:1

我在 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
c pointers memory
1个回答
0
投票

您通常无法通过编写代码并在(单个)系统上运行来了解“64 位平台中的内存布局”。您可能会了解有关特定系统的内容,但通常 C 标准不会指定代码中的变量如何放置在内存中。其中很多留给了实施。换句话说,不同的(64 位)系统、不同的编译器、不同的编译器选项等可能会发生变化。对结论如此谨慎......

对于这个问题:

对我来说奇怪的是,每次 char 指针 p 递增时,p 指向的值与 i 相同,直到 p 移动“进入”变量 a。当在 p + 4 行时,它的值等于'A'。

假设:

  1. 您的系统使用 4 个字节

    int

  2. 您的系统对有符号整数使用 2 的补码编码

  3. 您的系统使用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

© www.soinside.com 2019 - 2024. All rights reserved.