2

我想使用 memcpy 在可能包含任意类型的数组中进行“类型不可知交换”。为什么它需要一个 const src 指针?

我写了自己的版本:

void copyBytes(char *x, char *y, int howMany){
  int i;
  for(i = 0; i<howMany; i++){
    *(x+i) = *(y+i);
  }
}

我的版本有问题吗?

4

3 回答 3

8

我的版本有问题吗?

我会这么说。这是一个批评。

void copyBytes(char *x, char *y, int howMany)

首先,您的指针是,这意味着除需要显式转换之外的char *任何指针类型。char *您应该使用void *, 指针类型被隐式转换为。

uint16_t a, b;

copyBytes(&a, &b, sizeof(a));  // &a and &b are uint16_t*, not char*.

其次,来源 ,y不是const,这意味着如果您传递const来源,您将收到警告。

char buf[512];
const char str[] = "Hello world";  // Contents of string are constant.
copyBytes(buf, str, sizeof(str));  // With your code, this produces a warning.

第三,howMany是有符号的,意思是你可以传递一个负值。

我会推荐这样的签名(顺便说一下,这与 非常相似memcpy):

void copyBytes(void *x, const void *y, size_t howMany)

第四个批评... libcmemcpy可能会得到更好的优化,使用大于字节的单元、特定于平台的性能技巧(例如:内联汇编、x86 上的 SSE)等。memmove当缓冲区重叠。

总结:为学习目的自己编写这些例程很好,但使用 C 库通常会好得多。

于 2013-09-23T00:06:30.490 回答
6

“要求”?“要求”是一个错误的词。memcpy不需要src指针const。它允许一个constsrc 指针。允许constsrc 指针是一个较弱的规范,然后需要一个非常量 src 指针。它扩展了功能的适用性,而不是限制它。

需要一个非常量 src 指针会限制它的适用性memcpy——你不能将指向const数据的指针传递给你的函数(除非你使用丑陋的演员表)。为什么要提出这样的要求?memcpy不会修改 src 数据,因此允许将常量数据用作 src 的 src 是完全合乎逻辑的memcpy。这就是为什么memcpy将 src 指针声明为const.

在这种情况下,“require”一词实际上适用于您的版本。你的版本需要非常量指针作为 src 指针。并且由于这个额外的(并且完全不必要的)要求,您的版本不如memcpy. 例如

const char src_data[3] = { 1, 2, 3 };
char dst_data[3];

memcpy(dst_data, src_data, sizeof dst_data);    // Works
copyBytes(dst_data, src_data, sizeof dst_data); // Doesn't even compile
于 2013-09-23T00:30:59.393 回答
3

函数memcpy不会修改源内存。这意味着它不需要非常量指针,它允许常量指针和非常量指针。这不是对参数的限制,也不是对函数的适用性的限制。您可以在那里传递任何有效的数据指针。

这被编译器称为隐式转换。在您的特定情况下,const它是"Qualification conversion"

unqualified type can be converted to const

不允许从 const 指针到指针的相反隐式转换。注意这里的“隐含”一词。这意味着func(void *pointer)比 更具限制性func(void const *pointer)

如果您省略const限定符,您将利用编译器强加的类型安全性。编译器会警告您或其他人,传入 const 指针不是一个好主意。

如果您const在函数声明中使用限定符,则您承诺不会在那里修改数据。这对程序员来说是一个很好的提示,并提高了代码的可读性。然而,这只是一个承诺。一个糟糕的函数可能会通过在函数体中抛出 const-ness 来违反承诺。这在技术上是可行的,但很糟糕。

于 2013-09-23T00:03:04.920 回答