将char地址分配给一个int指针,从而写入一块int大小的内存

Assign char address to an int pointer, and consequently write an int-size piece of memory

摘自 Stroustrup - Programming: Principles and practices using C++ 一书。在§17.3中,关于内存、地址和指针应该允许分配一个char*int*:

char ch1 = 'a';
char ch2 = 'b';
char ch3 = 'c';
char ch4 = 'd';
int* pi = &ch3;   // point to ch3, a char-size piece of memory
*pi = 12345;      // write to an int-size piece of memory
*pi = 67890;

图形上我们有这样的东西:

引用来源:

Had the compiler allowed the code, we would have been writing 12345 to the memory starting at &ch3. That would definitely have changed the value of some nearby memory, such as ch2 or ch4, or we would have overwritten part of pi itself.

In that case, the next assignment *pi = 67890 would place 67890 in some completely different part of memory.


我不明白,为什么下一个作业会把它放在:内存中某个完全不同的部分int *pi中存储的地址仍然是&ch3,因此赋值将覆盖该地址的内容,即12345。为什么不是这样?

拜托,你能帮帮我吗?非常感谢!

您似乎跳过了您引用的部分解释:

or we would have overwritten part of pi itself

这样想,因为intchar大,如果一个int*指向一个存储char的地址位置,那么当您尝试为该位置分配一个整数值时,将会溢出内存,因为您只分配了一个字节的内存,但分配了 4 个字节的数据。也就是说,你不能将 4 个字节的数据放入一个,所以其他 3 个字节将放在某个地方。

然后假设溢出的字节部分改变了存储在pi中的值。现在下一个任务将转到一个随机的内存位置。

假设内存地址布局为:

0 1 2 3 4 5 6 7

从左起0、1、2、3为字符。从右边开始的 4、5、6 和 7 是一个 int*。 十六进制中每个字节的值可能是:

61 62 63 64 02 00 00 00

注意前四个是ascii值,后四个是ch3的地址。写入 *pi = 12345; 会像这样更改值:

61 62 39 30 00 00 00 00

其中 0x39300000 是小端十六进制的 12345。

下一次写入 *pi = 67890; 将从内存地址 00 00 00 00 开始,而不是预期的 02 00 00 00

首先,你必须明白一切都是数字,即charintint*都包含数字。内存地址也是数字。让我们假设当前示例编译并且我们有如下内存:

--------------------------
Address | Variable | Value
--------------------------
0x01   |    ch1       a
0x02   |    ch2       b
0x03   |    ch3       c
0x04   |    ch4       d
0x05   |    pi        &ch3 = 0x03

现在让我们取消引用 pi 并将新值重新分配给 ch3:

*pi = 12345;

我们假设 int 是 4 个字节。由于 pi 是一个 int 指针,它将向 pi 指向的位置写入一个 4 字节的值。现在,char 只能包含一个字节值,那么,如果我们尝试向该位置写入 4 个字节,会发生什么情况?严格来说,这是未定义的行为,但我会尝试解释作者的意思。

由于 char 不能包含大于 1 个字节的值,*pi = 12345 将溢出 ch3。当发生这种溢出时,4 个字节中剩余的 3 个字节可能会写入附近的内存位置。我们附近有哪些记忆位置? ch4pi 本身! ch4 也只能包含 1 个字节,剩下 2 个字节,下一个位置是 pi 本身。意思是 pi 会覆盖它自己的值!

--------------------------
Address | Variable | Value
--------------------------
0x01   |    ch1       a
0x02   |    ch2       b
0x03   |    ch3       12  //12 ended up here
0x04   |    ch4       34  //34 ended up here
0x05   |    pi        &ch3 = 0x03 // 5 gets written here

如您所见,pi 现在指向其他一些绝对不是 ch3 的内存地址。

char ch3 = 'c';
int* pi = &ch3;

it is supposed to be allowed to assign a char* to int*:

不完全是 - 存在对齐问题。 未定义行为 (UB) 当

If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. C17dr § 6.3.2.3 7

示例:某些处理器要求 int * 为偶数,如果 &ch3 为奇数,则存储地址 可能 失败,并且 de-referencing地址肯定失败:bus error.


下一个肯定是 UB,因为目的地在 ch3 的内存之外。
ch1, ch2, ch4 可能就在附近并提供一些合理的 未定义的行为 ,但结果是 UB。

// undefined behavior
*pi = 12345;      // write to an int-size piece of memory`

当代码尝试在其边界之外写入时 - 它是 UB,任何事情都可能发生,包括写入相邻数据。

The address stored in int *pi is still &ch3

也许,也许不是。 UB 发生了。

why the next assignment would place it: in some completely different part of memory?

滥用代码暗示 pi 本身被 *pi = 12345; 覆盖。这可能会发生,也可能不会。是UB。 *pi 的后续使用只是更多 UB。


回忆一下 UB,你可能会得到你希望的,你可能不会 - 它不是由 C 定义的。