了解记忆
Understanding memcpy
int a = 10;
int* pA = &a;
long long b = 200;
long long* pB = &b;
memcpy (pB,pA,4);
memcpy (pB+1,pA,4);
cout<<"I'm a memcpy!: "<<*(pB)<<endl;
我正在用memcpy做一些测试,以自学记忆是如何工作的。 我想做的是使b =到"1010"。 我可以将值从 a 复制到 b,但随后我尝试将内存偏移 1 个字节并再写入 10 个字节,但它不起作用,它只输出"10"。
我需要做什么才能获得值 1010?
你的代码存在一些问题:
- 您复制 4 个字节,但目标为
int
型。 由于int
不能保证是任何特定大小,因此您需要确保它至少为4字节,然后再执行此类memcpy
。 -
memcpy
在字节级别工作,但整数是一系列字节。 根据您的目标体系结构,整数中的字节可能会以不同的方式排列(大端序、小端序等)。 对整数使用memcpy
可能会也可能不会执行预期操作。 在学习memcpy
和朋友的工作方式时,最好使用字节数组。 - 您的第二个
memcpy
使用pB+1
作为目标。 这不会将指针前进一个字节,而是将其前进sizeof(*pB)
个字节。 在这种情况下,它会指向一个无效的地址(超过变量的末尾)。 这种对memcpy
的调用将损坏随机内存,这可能会使程序崩溃或导致不可预知的结果。
我不认为memcpy()
是为你想要的而设计的。 通常,您将使用 memcpy()
来复制一个或多个完整对象(其中对象可能是 int、char、long long 等)
int a[4] = { 1, 2, 3, 4 };
int b[3];
int c[5] = { 0 };
::memcpy(b, a, 3 * sizeof(int)); // b is { 1, 2, 3 }
::memcpy(c+2, b, 3 * sizeof(int)); // c is { 0, 0, 1, 2, 3 }
C+2 不是"C + 2 字节"。 它是"c + 2 ints"(Win32/x86 系统上为 8 个字节)。
您可以通过转换为 char 或无符号 char 指针来访问各个字节,但我不建议这样做,除非您真正了解自己在做什么,因为有很多陷阱。
unsigned x = 0;
unsigned char *px = reinterpret_cast<unsigned char *>(&x);
px[0] = 0xFF;
px[2] = 0xAA;
这里的危险之一是您假设计算机如何存储整数的知识。 在 x86 系统上,x 将被0x00AA00FF但在 Sun Sparc 系统上,它将是0xFF00AA00。
如果您需要设置整数的一部分,通常最好使用"or"和"shift"。
x = (0xFF<<24) | (0xAA<<8);
将为您提供任何架构0xFF00AA00。0xFF<<24 将0xFF的值向左移动 24 位,从而0xFF000000。0xAA<<8 将0xAA的值向左移动 8 位,从而0x0000AA00。
我们一起"或"他们,给予0xFF00AA00。
查看指针算法:http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html 。向指针添加一个值实际上会增加您正在处理的任何大小的单位。
pB 的类型是 long long*,因此向其添加 1 将给出变量 b 之后的下一组八个字节的地址。 你有 pB[0] 是变量 b,但 pB[1](相当于 pB+1)指向未定义的内存。 写入它可能会导致崩溃。
取代
long long b;
跟
long long b[2];
(使用您喜欢的任何初始值)
你的口水需要同时喂食 b[0] 和 b[1]。
如果要将"10"复制到字节并得到"1010",则需要复制字符串。 这确实是strcat()
而不是memcpy()
的工作,但这里有一种方法可以用memcpy()
来做到这一点:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
constexpr char src[] = "10";
constexpr size_t n = sizeof(src) - 1; // Don’t count the terminator.
char dest[2*n+1] = {' '}; // Will hold: {'1','0','1','0',' '}
static_assert( sizeof(dest) > 2*n, "" ); // Always check array bounds in C++!
memcpy( dest, src, n );
memcpy( dest + n, src, n );
puts(dest);
return EXIT_SUCCESS;
}
特别是,请注意目标是一个足够长的字节数组,可以容纳两个副本。
我没有声誉得分>= 50,所以我无法发表评论,即使作为评论帖子的原作者 ->在我看来这简直是愚蠢的......
因此,这是我对user207421发布的评论的回答:
-
在过去 20 年(至少)中,PC 中使用的每个 CPU 都实现了 SIMD 指令,因此除非您使用的是一些非常旧的 CPU,否则您关于"足够新"的 CPU 的说法基本上是无效的。
-
请参阅我上面帖子中的第 2 点:"最快的架构相关方法"意味着在 8 位 AVR 上,"movw"指令可以(并且它)用于实现类似 memcpy 的快速功能,因为它的工作方式类似于 x86 上的 SIMD:它可以在一个周期内复制 2 个 8 位 CPU 字。
问候。
memcpy 在字节级别工作,但整数是一系列字节。
错误的解释。
对于strcpy()
来说,上面的答案或多或少是正确的,但在memcpy()
的情况下是完全错误的,因为所有mem_xxx()
函数都在使用 SIMD 指令来加速操作。
如果memcpy()
函数基于逐字节复制,那将是致命的慢......
基本上,所有mem_xxx
函数都是这样实现的:
- 如果源和/或目标指针未对齐,则这些函数通过首先处理未对齐/奇数内存块来对齐指针。
- 接下来,使用最快的依赖于体系结构的方法来处理对齐的内存区域。
- 最后,处理剩余的未对齐/奇数字节。
我建议在发布错误答案之前实际阅读代码。
- 正在尝试了解输入验证循环
- 了解 GLM- openGL 中的相机转换
- C++我需要了解在哪里使用指针和双指针
- 如何深入了解明显的腐败
- 松弛原子与无同步情况下的记忆连贯性
- 了解嵌套循环打印星号图案
- 递归函数有效,但无法记忆
- 了解每月第一天函数的代码
- 了解C++标准::shared_ptr
- 如何将记忆应用于此递归函数?
- 尝试了解在导入的静态方法上使用删除方法时的错误
- C++:需要帮助了解运算符重载错误
- 在学习数据结构之前对STL有一个了解是好的吗?
- 了解算法的性能差异(如果以不同的编程语言实现)
- 了解删除C++
- 共享记忆:让我们谈谈它的特殊性
- 了解内存序列和标准::memory_order_relaxed
- 了解其工作原理
- 准确了解对象在内存中的映射方式
- 了解记忆