字节和地址在 C 中如何关联?

How do bytes and addresses correlate in C?

我看到有很多与这个主题相关的问题,但我无法推断出答案,所以我决定在这里问我的第一个问题关于堆栈溢出。目前,我的问题是关于字节和地址,每个地址是否实际上代表一个地址,这意味着如果我要初始化一个地址,例如0x55555555d156 但如果我要初始化一个 int,它将需要 4 个地址,这意味着它的范围从例如0x55555555d156 0x55555555d160 ?所以让我困惑的是,一个指针会保存一个地址,对吧?

假设指针保存地址,例如0x55555555d156 如果我要引用那个地址,我会得到那个 int 的值,对吧?如果我尊重其他 3 个地址呢?我无法通过编写 C 程序来获取该信息。

if I were to deference that address I would get the value of that int, right?

是的。

what about the other 3 addresses, if I deference them?

如果您有 int *p = &some_integer;,那么 *(int *)((char *)p + 1)(取消引用 p“移位”一个 字节)将尝试读取 4 个字节从那个新地址并将它们解释为一个整数。您的程序是否具有 权限 来读取内存中 some_integer 旁边的最后一个字节,这是另一回事:如果没有,您将遇到分段错误或其他内存访问问题。

或者你可能没有得到任何错误并读取垃圾数据。

例子

#include <stdio.h>

int main(void) {
    int my_int = 0x12345678;
    int *ptr = &my_int;

    printf("%x\n", *ptr);
    printf("%x\n", *(int *)((char *)ptr + 1));
}

输出:

~/test $ clang so.c && ./a.out
12345678
80123456
^^
 |-- This "random" byte was read as part of
 --- the "new" int shifted by 1 byte

不同的微处理器具有不同的可寻址内存单元。大多数,包括 x86 系列和 ARM,都可以以一个字节为单位进行寻址。因此,例如,一个 32 位 int 将存储在四个连续的内存地址中(LSB 在前,除非 ARM 设置为“Big Endian”模式)。

其他处理器,如 PIC,可能有一个地址指向一个 16 位内存字。

您的 C 代码可能不应该以任何一种方式做出假设,除非您确定代码 运行 的内容。

您不能“取消引用地址”——您可以取消引用指针。指针值是地址,但指针也有类型。取消引用的结果取决于指针的类型。

取消引用指针的结果不是存储在所指向的内存位置的值。它是指定对象的表达式。这在 C 中称为 lvalue

如果这一切都不清楚;首先检查您是否了解代码中发生的事情:

int x = 0;

x = 5;

在第二行中,使用 x 不会检索值 0。表达式 x 是一个 lvalue ,这意味着它指定了一个由几个字节组成的内存区域。每个字节都有自己的地址。如果你输出 &x ,你可能会看到与输出 x 第一个字节的地址相同的结果(尽管这不是标准要求),但类型不同。

当左值表达式出现在代码中时,是否检索存储的值取决于表达式的上下文。例如,如果它出现在赋值运算符的左侧,则不会检索该值。

一旦你理解了 x = 5; ,那么 *p = 5; 的行为就相同了; *p 的含义就好像标签 x 存在于 p 指向的内存区域一样。