函数memmove
的定义如下:
void *memmove(void *dest, const void *src, size_t n);
在Linux手册页中,它说:
返回值
memmove()函数返回指向dest的指针。
为什么当函数总是返回其中一个输入参数时,该函数才被定义为void memmove(…)
?返回值可以与dest
不同吗?
或者返回值是否总是dest
而且只是为了能够以某种创造性的方式组合函数?
答案 0 :(得分:42)
memmove
永远不会返回dest
以外的任何内容。
当第一个参数是计算表达式时,返回dest
而不是使memmove
为空是有用的,因为它允许您避免先计算相同的值,并将其存储在变量中。这可以让你在一行中完成
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);
答案 1 :(得分: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
的值。
因此,函数将始终返回指向目标缓冲区的指针,这是设计的。
现在进入 why 部分,许多函数都是以这种方式设计的,可以使函数调用链接成为可能。这样,您可以调用memmove()
作为另一个函数的参数,其中复制的值(即指向dest
的指针)将属于某些函数使用
例如,您可以编写较短的
puts(memmove(dest_buffer, src_buffer, welcome_message_size));
而不是更长的
memmove(dest_buffer, src_buffer, welcome_message_size);
puts(dest_buffer);
答案 2 :(得分:13)
返回其中一个参数(指针类型)的确切值的习惯用法是为了支持“链式”函数调用(另请参阅strcpy
,strcat
等)。它允许您将一些重复代码编写为单个表达式语句,而不是将其拆分为多个语句。例如
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中引入复合文字之后,这个习语的价值有所增加。对于复合lterals,这个习惯用法允许用户编写相同的代码而不引入命名的中间变量
printf("%s\n", strcat(strcat(strcpy((char [1024]) { 0 }, "Hello"), " "), "World!"));
some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data));
这是有道理的,因为在大多数情况下,命名变量应该是短命的,之后不需要,并且只会混淆命名空间。