memcpy 启动索引真的需要吗?

memcpy start index really needed?

问题是当我们使用 memcpy() 复制任何字节数组时,我们应该显式声明目标缓冲区的起始(第 0 个)索引还是简单地提及它就足够了。让我展示我在说什么的例子。假设我们正在尝试将源缓冲区复制到目标缓冲区的开头。

BYTE *pucInputData; // we have some data here
BYTE ucOutputData[20] = {0};

代码 1

memcpy((void*)&ucOutputData, (void*)pucInputData, 20);

代码 2

memcpy((void*)&ucOutputData[0], (void*)pucInputData, 20);

在你的例子中,考虑到这是一个 C 代码片段,ucOutputData 是一个数组

  • memcpy(ucOutputData, pucInputData, 20);
  • memcpy(&ucOutputData[0], pucInputData, 20);

两者相同并且可以互换使用。数组的名称实质上为您提供了数组中第一个元素的地址。

现在,根据下面评论中非常有用的讨论,值得一提的是,

memcpy(&ucOutputData, pucInputData, 20);

也会在这里完成这项工作,但是数组名称的用法之间存在根本区别数组名称的地址。考虑问题中的示例,对于 BYTE ucOutputData[20]

这样的定义
  • ucOutputData指向20BYTE个数组的首元素地址。
  • &ucOutputData是一个指向20个BYTE数组的指针。

所以,它们是不同的类型,C 尊重变量的类型。因此,为避免任何可能的误用和误解,推荐和安全的使用方法是前两个表达式之一。

FWIW,真的不需要这里的演员表。任何指针类型都可以隐式安全地转换为 C 中的 void *

因为表达式 &array[0]array 相同,并且因为任何指针都可以隐式转换为 void*,所以您应该这样做:

memcpy(ucOutputData, pucInputData, 20);

此外,由于您正在覆盖整个 ucOutputData,因此不需要将其内容置零,因此可以删除初始化程序:

BYTE ucOutputData[20]; // no "= {0}" part

原生数组可以在不进行转换的情况下衰减为指针,因此在下面的代码片段中,对 p 的三个赋值都会产生相同的值; p 将指向数组的开头。不需要显式转换,因为转换为 void* 是隐式的。

typedef char BYTE;
BYTE ucOutputData[20] = {0};

void *p = &ucOutputData;
p = ucOutputData;
p = &ucOutputData[0];

不,你的两个例子都不是最优的。

请记住,C 中的所有数据指针都可以在不丢失信息的情况下转换 to/from void *(这是 memcpy() 的第一个参数的类型),并且不需要强制转换这样做。

另请记住,在许多情况下,数组名称的计算结果为第一个元素的地址,例如此处。

还请记住尽可能使用 sizeof,不要在不必要时引入文字常量。

所以,副本应该是:

memcpy(ucOutputData, pucInputData, sizeof ucOutputData);

请注意,我们使用不带括号的 sizeof,它不是函数。我们还在 destination 缓冲区上使用它,这似乎是更安全的选择。