7
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

7 回答 7

9

您的代码存在一些问题:

  • 您复制 4 个字节,但目标是 type int。由于int不保证是任何特定大小,因此在执行那种memcpy.
  • memcpy在字节级别上工作,但整数是一系列字节。根据您的目标架构,整数中的字节可能会以不同的方式排列(大端、小端等)。在整数上使用memcpy可能会也可能不会达到您的预期。memcpy学习和朋友如何工作时最好使用字节数组。
  • 您的第二次memcpy使用pB+1作为目标。这不会使指针前进一个字节,而是按sizeof(*pB)字节前进。在这种情况下,它会指向一个无效的地址(在变量末尾之后)。此调用memcpy将损坏随机内存,这可能会使您的程序崩溃或导致不可预知的结果。
于 2012-06-14T00:05:27.010 回答
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 系统上,x 将为 0xFF00AA00。

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

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

在任何架构上都会给你 0xFF00AA00 。0xFF<<24 将值 0xFF 向左移动 24 位,形成 0xFF000000。0xAA<<8 将值 0xAA 向左移动 8 位,形成 0x0000AA00。

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

于 2012-06-14T00:30:09.083 回答
1

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

于 2012-06-14T00:03:16.317 回答
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]。

于 2012-06-14T00:05:04.577 回答
0

如果您想将“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] = {'\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;
}

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

于 2018-03-26T00:19:12.653 回答
0

我的声誉得分不 >= 50,所以我不能发表评论,即使是评论帖子的原作者 -> 从我的角度来看,这简直是愚蠢的......

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

  1. 过去 20 年(至少)在 PC 中使用的每个 CPU 中都实现了 SIMD 指令,因此除非您使用一些非常旧的 CPU,否则您关于“足够新”的 CPU 的声明基本上是无效的。

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

问候。

于 2020-05-01T21:08:51.420 回答
-1

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

错误的解释。

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

如果该memcpy()功能基于逐字节复制,那将是致命的慢...

基本上,所有的mem_xxx功能都是这样实现的:

  1. 如果源和/或目标指针未对齐,则这些函数通过首先处理未对齐/奇数内存块来对齐指针。
  2. 接下来,使用最快的架构相关方法来处理对齐的内存区域。
  3. 最后,处理剩余的未对齐/奇数字节。

我建议在发布错误答案之前实际阅读代码。

于 2018-02-18T22:59:15.963 回答