39

函数memmove定义如下:

void *memmove(void *dest, const void *src, size_t n);

在 Linux 手册页中,它说:

返回值
memmove() 函数返回一个指向 dest 的指针。

为什么函数不只是定义为void memmove(…)它总是返回输入参数之一?返回值可以与 不同dest吗?

还是返回值真的总是dest如此,只是为了能够以一些创造性的方式组合函数?

4

3 回答 3

43

memmove永远不会返回除dest.

当第一个参数是计算表达式时,返回dest而不是memmovevoid 很有用,因为它可以避免预先计算相同的值并将其存储在变量中。这使您可以在一行中完成

void *dest = memmove(&buf[offset] + copiedSoFar, src + offset, sizeof(buf)-offset-copiedSoFar);

否则您需要在两行上做的事情:

void *dest = &buf[offset] + copiedSoFar;
memmove(dest, src + offset, sizeof(buf)-offset-copiedSoFar);
于 2016-10-12T13:36:18.877 回答
26

根据C11§7.24.2.1 和 §7.24.2.2 章

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

[...] 该memcpy函数返回s1.

和,

void *memmove(void *s1, const void *s2, size_t n);

[...] 该memmove函数返回s1.

因此,函数将始终返回指向目标缓冲区的指针,这是设计使然。

现在来到为什么部分,许多函数都是以这种方式设计的,以使函数调用的链接成为可能。这样,您可以调用 tomemmove()作为另一个函数的参数,其中复制的值(即指向 的指针dest)将有一些用处。

例如,您可以写较短的

 puts(memmove(dest_buffer, src_buffer, welcome_message_size));

而不是更长的

 memmove(dest_buffer, src_buffer, welcome_message_size);
 puts(dest_buffer);
于 2016-10-12T13:33:05.080 回答
13

存在返回参数之一(指针类型)的确切值的习惯用法是为了支持“链式”函数调用(另见strcpystrcat)。它允许您将一些重复的代码编写为单个表达式语句,而不是将其拆分为多个语句。例如

char buffer[1024];
printf("%s\n", strcat(strcat(strcpy(buffer, "Hello"), " "), "World"));

struct UserData data_copy;
some_function(memcpy(&data_copy, &original_data, sizeof original_data));

即使您不喜欢这种组织代码的方式并且更喜欢通过多个语句来做同样的事情,返回一个 [不必要的] 指针值的开销实际上是不存在的。

甚至可以说,在 C99中引入复合文字之后,这个成语的价值增加了​​一点。使用复合字元,这个习惯用法允许人们编写相同的代码而不引入命名的中间变量

printf("%s\n", strcat(strcat(strcpy((char [1024]) { 0 }, "Hello"), " "), "World!"));

some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data));

这是有道理的,因为在大多数情况下,命名变量应该是短暂的,之后就不需要了,只会使命名空间变得混乱。

于 2016-10-12T14:28:37.157 回答