将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
这样想,因为int
比char
大,如果一个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
。
首先,你必须明白一切都是数字,即char
、int
、int*
都包含数字。内存地址也是数字。让我们假设当前示例编译并且我们有如下内存:
--------------------------
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 个字节可能会写入附近的内存位置。我们附近有哪些记忆位置? ch4
和 pi
本身! 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 定义的。
摘自 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 asch2
orch4
, or we would have overwritten part ofpi
itself.
In that case, the next assignment
*pi = 67890
would place67890
in some completely different part of memory.
我不明白,为什么下一个作业会把它放在:内存中某个完全不同的部分? int *pi
中存储的地址仍然是&ch3
,因此赋值将覆盖该地址的内容,即12345
。为什么不是这样?
拜托,你能帮帮我吗?非常感谢!
您似乎跳过了您引用的部分解释:
or we would have overwritten part of pi itself
这样想,因为int
比char
大,如果一个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
。
首先,你必须明白一切都是数字,即char
、int
、int*
都包含数字。内存地址也是数字。让我们假设当前示例编译并且我们有如下内存:
--------------------------
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 个字节可能会写入附近的内存位置。我们附近有哪些记忆位置? ch4
和 pi
本身! 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 定义的。