为什么memcpy需要const void指针?

时间:2013-09-23 00:01:29

标签: c

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

我写了自己的版本:

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

我的版本有问题吗?

3 个答案:

答案 0 :(得分:7)

  

我的版本有问题吗?

我会这么说。这是批评。

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)

第四个批评...... libc的memcpy可能会更好地优化,使用大于字节的单位,特定于平台的性能技巧(例如:内联汇编,x86上的SSE)等。还有memmove,当缓冲区重叠时,它具有更好的指定行为。

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

答案 1 :(得分:6)

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

要求非const src指针会限制memcpy的适用性 - 您将无法将const数据的指针传递给您的函数(除非您使用丑陋的转换)。你为什么要引入这样的要求? memcpy不会修改src数据,因此将允许常量数据用作memcpy的src是完全合乎逻辑的。这就是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

答案 2 :(得分:3)

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

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

unqualified type can be converted to const

不允许从const指针到指针的隐式转换。请注意“隐式”字样。这意味着func(void *pointer)func(void const *pointer)更具限制性。

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

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