memcpy 中的指针运算有奇怪的结果
Pointer arithmetic in memcpy has weird result
几年后我又回到了 C 编程,所以我想我有点生疏了,但我在我的代码中看到了一些奇怪的行为。
我有以下内容:
memcpy(dest + (start_position * sizeof(MyEnum)), source, source_size * sizeof(MyEnum));
其中:
dest
和source
是不同大小的MyEnum
数组,
dest
是 64 字节长。
source
是 16 个字节长。
sizeof(MyEnum)
是 4
字节
source_size
是 4
,因为数组中有 4 个枚举。
我将此代码循环 4 次,每次都推进 start_position
,因此在 4 次循环迭代中的每一次中,我都会使用以下值调用 memcpy
(我已经用调试器):
memcpy(dest + (0), source, 16);
(start_position
= 0 * 4,因为 source
大小为 4)
memcpy(dest + (16), source, 16);
(start_position
= 1 * 4,因为 source
大小为 4)
memcpy(dest + (32), source, 16);
(start_position
= 2 * 4,因为 source
大小为 4)
memcpy(dest + (48), source, 16);
(start_position
= 3 * 4,因为 source
大小为 4)
memcpy
在第一个循环中工作正常,但在第二个循环中它将数据复制到另一个数组,显然超出了 dest
数组的内存区域,侵犯了另一个数组的内存区域。
所以我检查了函数内部发生的指针运算,这就是我得到的:
dest
地址是0xbeffffa74
dest + (start_position * sizeof(MyEnum))
是 0xbefffab4
对于 (start_position * sizeof(MyEnum)
= 16
- 被侵犯的数组位于
0xbefffab4
。
尽管这解释了数组内存被侵犯的原因,但我不明白 0xbeffffa74 + 16
将如何成为 0xbefffab4
,但我可以确认那是 memcpy
的地址正在被调用。
我 运行 在 Raspberry Pi 上,但据我所知,这不重要。
指针运算适用于指向的数据类型的大小。如果你有一个 char*
那么每次你增加指针它都会移动一个。如果它是一个 int*
那么每个增量增加一个以上,通常是 4 到指针(由于 int 通常,但不总是,是 32 位)。
如果您有一个指向结构的指针,则递增指针会将其移动结构的大小。因此 sizeof
不应该在那里,否则你会移动太多。
memcpy(dest + (start_position * sizeof(MyEnum)), source, source_size * sizeof(MyEnum));
由于 MyEnum
是四个字节,因此每个位置都将指针移动 4*4 个字节。
memcpy(dest + start_position, source, source_size * sizeof(MyEnum));
这一次只移动 4 个字节。
这是合乎逻辑的,因为 pointer[2]
与 *(pointer + 2)
相同,所以如果指针运算没有隐式地考虑指向的类型大小,所有索引也将需要 sizeof
和你最终会写很多 pointer[2 * sizeof(*pointer)]
.
几年后我又回到了 C 编程,所以我想我有点生疏了,但我在我的代码中看到了一些奇怪的行为。
我有以下内容:
memcpy(dest + (start_position * sizeof(MyEnum)), source, source_size * sizeof(MyEnum));
其中:
dest
和source
是不同大小的MyEnum
数组,dest
是 64 字节长。source
是 16 个字节长。sizeof(MyEnum)
是4
字节source_size
是4
,因为数组中有 4 个枚举。
我将此代码循环 4 次,每次都推进 start_position
,因此在 4 次循环迭代中的每一次中,我都会使用以下值调用 memcpy
(我已经用调试器):
memcpy(dest + (0), source, 16);
(start_position
= 0 * 4,因为source
大小为 4)memcpy(dest + (16), source, 16);
(start_position
= 1 * 4,因为source
大小为 4)memcpy(dest + (32), source, 16);
(start_position
= 2 * 4,因为source
大小为 4)memcpy(dest + (48), source, 16);
(start_position
= 3 * 4,因为source
大小为 4)
memcpy
在第一个循环中工作正常,但在第二个循环中它将数据复制到另一个数组,显然超出了 dest
数组的内存区域,侵犯了另一个数组的内存区域。
所以我检查了函数内部发生的指针运算,这就是我得到的:
dest
地址是0xbeffffa74
dest + (start_position * sizeof(MyEnum))
是0xbefffab4
对于(start_position * sizeof(MyEnum)
=16
- 被侵犯的数组位于
0xbefffab4
。
尽管这解释了数组内存被侵犯的原因,但我不明白 0xbeffffa74 + 16
将如何成为 0xbefffab4
,但我可以确认那是 memcpy
的地址正在被调用。
我 运行 在 Raspberry Pi 上,但据我所知,这不重要。
指针运算适用于指向的数据类型的大小。如果你有一个 char*
那么每次你增加指针它都会移动一个。如果它是一个 int*
那么每个增量增加一个以上,通常是 4 到指针(由于 int 通常,但不总是,是 32 位)。
如果您有一个指向结构的指针,则递增指针会将其移动结构的大小。因此 sizeof
不应该在那里,否则你会移动太多。
memcpy(dest + (start_position * sizeof(MyEnum)), source, source_size * sizeof(MyEnum));
由于 MyEnum
是四个字节,因此每个位置都将指针移动 4*4 个字节。
memcpy(dest + start_position, source, source_size * sizeof(MyEnum));
这一次只移动 4 个字节。
这是合乎逻辑的,因为 pointer[2]
与 *(pointer + 2)
相同,所以如果指针运算没有隐式地考虑指向的类型大小,所有索引也将需要 sizeof
和你最终会写很多 pointer[2 * sizeof(*pointer)]
.