memcpy 中的指针运算有奇怪的结果[重复]
Posted
技术标签:
【中文标题】memcpy 中的指针运算有奇怪的结果[重复]【英文标题】:Pointer arithmetic in memcpy has weird result [duplicate] 【发布时间】:2019-09-15 06:01:41 【问题描述】:几年后我又回到了 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 上运行它,但 AFAIK 这应该没关系。
【问题讨论】:
【参考方案1】:指针算法适用于指向数据类型的大小。如果你有一个char*
,那么每次你增加指针它都会移动一个。如果它是一个int*
,那么每个增量都会增加一个以上的指针,通常是 4(由于 int 通常是 32 位,但并非总是如此)。
如果你有一个指向结构的指针,那么递增指针会移动结构的大小。因此sizeof
不应该在那里,否则你会移动太多。
memcpy(dest + (start_position * sizeof(MyEnum)), source, source_size * sizeof(MyEnum));
这会将指针每个位置移动 4*4 字节,因为 MyEnum
是四个字节。
memcpy(dest + start_position, source, source_size * sizeof(MyEnum));
这一次只移动 4 个字节。
这是合乎逻辑的,因为pointer[2]
与*(pointer + 2)
相同,因此如果指针算法没有隐式考虑指向的类型大小,所有索引也需要sizeof
,你最终会写很多pointer[2 * sizeof(*pointer)]
.
【讨论】:
a[b]
与 *(a+b)
相同。这意味着(a+b)
必须与&a[b]
相同。现在,考虑int a[2];
。如果你想要a
的第二个元素,你可以使用a[1]
而不是a[1* sizeof(int)]
。这意味着*(a+1)
,而不是*(a+1*sizeof(int))
。因此,对于第二个元素的地址(a+1)
,而不是(a+1*sizeof(int))
。那么,如果你不乘以sizeof(int)
,为什么还要乘以sizeof(myEnum)
?
是的,从这个角度来看完全有道理,我只是忘记了经典的*(a+b)
,只是在考虑字节。太糟糕了,我在这个问题上被否决了,因为这里的答案似乎比重复的答案要好得多。以上是关于memcpy 中的指针运算有奇怪的结果[重复]的主要内容,如果未能解决你的问题,请参考以下文章