memcpy 或 memmove return 可以是与 dest 不同的指针吗?
Can memcpy or memmove return a different pointer than dest?
函数memmove
定义如下:
void *memmove(void *dest, const void *src, size_t n);
在 Linux 手册页中,它说:
RETURN VALUE
The memmove() function returns a pointer to dest.
当函数总是 return 输入参数之一时,为什么它不直接定义为 void memmove(…)
? return 值可以不同于 dest
吗?
或者 return 值真的总是 dest
并且只是为了能够以一些创造性的方式组合函数吗?
根据 C11
,章节 §7.24.2.1 和 §7.24.2.2
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
[...] The memcpy
function returns the value of s1
.
并且,
void *memmove(void *s1, const void *s2, size_t n);
[...] The memmove
function returns the value of s1
.
因此,函数将始终 return 指向目标缓冲区的指针,这是设计使然。
现在来到 why 部分,许多函数都是这样设计的,以使函数调用链接成为可能。这样,您可以调用 memmove()
作为另一个函数的参数,其中复制的值(,即指向 dest
的指针)将有点用处。
比如你可以写短一点的
puts(memmove(dest_buffer, src_buffer, welcome_message_size));
而不是更长的
memmove(dest_buffer, src_buffer, welcome_message_size);
puts(dest_buffer);
memmove
永远不会 return 除了 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);
为了支持 "chained" 函数调用(另见 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引入复合字面值后,这个成语的价值又增加了一点。对于复合字母,这种惯用语允许人们在不引入命名中间变量的情况下编写相同的代码
printf("%s\n", strcat(strcat(strcpy((char [1024]) { 0 }, "Hello"), " "), "World!"));
some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data));
这是有道理的,因为在大多数情况下命名变量应该是短暂的,之后就不需要了,只会弄乱命名空间。
函数memmove
定义如下:
void *memmove(void *dest, const void *src, size_t n);
在 Linux 手册页中,它说:
RETURN VALUE
The memmove() function returns a pointer to dest.
当函数总是 return 输入参数之一时,为什么它不直接定义为 void memmove(…)
? return 值可以不同于 dest
吗?
或者 return 值真的总是 dest
并且只是为了能够以一些创造性的方式组合函数吗?
根据 C11
,章节 §7.24.2.1 和 §7.24.2.2
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
[...] The
memcpy
function returns the value ofs1
.
并且,
void *memmove(void *s1, const void *s2, size_t n);
[...] The
memmove
function returns the value ofs1
.
因此,函数将始终 return 指向目标缓冲区的指针,这是设计使然。
现在来到 why 部分,许多函数都是这样设计的,以使函数调用链接成为可能。这样,您可以调用 memmove()
作为另一个函数的参数,其中复制的值(,即指向 dest
的指针)将有点用处。
比如你可以写短一点的
puts(memmove(dest_buffer, src_buffer, welcome_message_size));
而不是更长的
memmove(dest_buffer, src_buffer, welcome_message_size);
puts(dest_buffer);
memmove
永远不会 return 除了 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);
为了支持 "chained" 函数调用(另见 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引入复合字面值后,这个成语的价值又增加了一点。对于复合字母,这种惯用语允许人们在不引入命名中间变量的情况下编写相同的代码
printf("%s\n", strcat(strcat(strcpy((char [1024]) { 0 }, "Hello"), " "), "World!"));
some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data));
这是有道理的,因为在大多数情况下命名变量应该是短暂的,之后就不需要了,只会弄乱命名空间。