了解memcpy

时间:2012-06-13 23:54:34

标签: c++ memory 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?

7 个答案:

答案 0 :(得分:9)

您的代码存在一些问题:

  • 您复制了4个字节,但目标是int类型。由于int不保证是任何特定大小,因此在执行此类memcpy之前,您需要确保它至少有4个字节。
  • memcpy适用于字节级别,但整数是一系列字节。根据您的目标体系结构,整数内的字节可能会以不同的方式排列(big-endian,little-endian等)。在整数上使用memcpy可能会也可能不会达到预期效果。在学习memcpy和朋友的工作方式时,最好使用字节数组。
  • 您的第二个memcpy使用pB+1作为目标。这不会使指针前进一个字节,而是将其提前sizeof(*pB)个字节。在这种情况下,它使它指向一个无效的地址(超过变量的末尾)。对memcpy的此调用将破坏随机内存,这可能会导致程序崩溃或导致不可预测的结果。

答案 1 :(得分:2)

我认为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或unsigned char指针来访问各个字节,但除非你真正理解你正在做什么,否则我不建议这样做,因为存在许多陷阱。

    unsigned x = 0;
    unsigned char *px = reinterpret_cast<unsigned char *>(&x);

    px[0] = 0xFF;
    px[2] = 0xAA;

这里的一个危险是您正在假设计算机如何存储整数。在x86系统上,x将为0x00AA00FF,但在Sun Sparc系统上,它将为0xFF00AA00。

如果您需要设置整数的部分,通常最好使用“或”和“shift”。

    x = (0xFF<<24) | (0xAA<<8);

将在任何架构上为您提供0xFF00AA00。 0xFF&lt;&lt; 24将值0xFF向左移24位,产生0xFF000000。 0xAA&lt;&lt; 8将值0xAA向左移8位,产生0x0000AA00。

我们“或”他们在一起,给出0xFF00AA00。

答案 2 :(得分:1)

查看指针算术:http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html。向指针添加值实际上会增加您正在处理的任何大小的单位。

答案 3 :(得分:0)

pB的类型为long long *,因此向它添加1将为变量b后面的下一组8个字节提供地址。你有pB [0]是变量b,但是pB [1](相当于pB + 1)指向未定义的内存。写入它可能会导致崩溃。

替换

long long b;

long long b[2];

(使用您喜欢的任何初始值)

你的cout需要同时喂b [0]和b [1]。

答案 4 :(得分:0)

如果你想复制&#34; 10&#34;以后到字节并得到&#34; 1010&#34;,你想要复制字符串。这实际上是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] = {'\0'}; // Will hold: {'1','0','1','0','\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;
}

特别是,请注意目标是一个足以容纳两个副本的字节数组。

答案 5 :(得分:0)

我的信誉评分> = 50,所以我也无法发表评论,即使是被评论的帖子的原始作者->从我的角度来看这也是愚蠢的...

因此,这是我对user207421发表的评论的回答:

  1. SIMD指令至少在最近20年中已在PC上使用的每个CPU中实现,因此,除非您使用的是非常个旧CPU,否则您对“ “ CPU基本上是无效的。

  2. 请参阅我上面的帖子中的第2点:“最快的依赖于体系结构的方法”意味着在8位AVR上,“ movw”指令可以(且用于)实现类似memcpy的快速功能,因为它的工作方式类似于x86上的SIMD:它可以在一个周期内复制2个8位CPU字

致谢。

答案 6 :(得分:-1)

  

memcpy在字节级别上工作,但整数是一系列字节。

错误的解释。

对于strcpy(),上述答案或多或少都是正确的,但在memcpy()的情况下完全错误,因为所有mem_xxx()函数都使用SIMD指令来加速操作。

如果memcpy()函数基于逐字节复制,那将会非常慢......

基本上,所有mem_xxx函数都是这样实现的:

  1. 如果源指针和/或目标指针未对齐,那么这些函数通过首先处理未对齐/奇数内存块来对齐指针。
  2. 接下来,使用最快的架构相关方法来处理对齐的内存区域。
  3. 最后,处理剩余的未对齐/奇数字节。
  4. 我建议在发布错误答案之前实际读取代码。