memcpy或memmove可以返回与dest不同的指针吗?

Mar*_*ing 38 c return-value function-call memmove

该函数memmove定义如下:

void *memmove(void *dest, const void *src, size_t n);
Run Code Online (Sandbox Code Playgroud)

在Linux手册页中,它说:

返回值
memmove()函数返回指向dest的指针.

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

或者返回值是否总是dest如此,只是能够以某种创造性的方式组合功能?

das*_*ght 42

memmove将永远不会返回任何其他东西dest.

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

void *dest = memmove(&buf[offset] + copiedSoFar, src + offset, sizeof(buf)-offset-copiedSoFar);
Run Code Online (Sandbox Code Playgroud)

你需要在两行上做什么:

void *dest = &buf[offset] + copiedSoFar;
memmove(dest, src + offset, sizeof(buf)-offset-copiedSoFar);
Run Code Online (Sandbox Code Playgroud)

  • @dasblinkenlight我称之为模糊而非惊人,至少对于C程序员以外的任何人来说都是如此.如果我想在一行中复制字符串,我宁愿只使用`strcpy`. (9认同)
  • 让它什么都不返回.这不是这个功能的关注点.字符串函数返回一个指针,因为指针是以O(N)方式计算的(如果我错了那个字符串函数也不应该返回一个指针). (6认同)
  • 这是一个非常弱的论点,IMO.如果您在代码审查中展示了我的第一个示例,我会要求您将其转换为第二个示例.为什么"memmove"的工作可以帮助你制作单行内容?一个更好的返回值就是`dest + n`,因为那时你可以将事物连在一起:`dest = memcpy(dest,...); dest = memcpy(dest ..); etc`. (5认同)
  • C中的一个衬里很有吸引力,有点好看,但它们应该被认为是艺术,而不是生产有价值的代码. (3认同)
  • @GManNickG对我而言,C之美的一大部分就在于其惊人的单行.我个人最喜欢的是`while((*dest ++ =*src ++));`用于字符串复制.一旦我看到最后的分号,我就被迷住了!我同意你的看法,返回缓冲区的末尾,而不是它的开头,会更有意义. (2认同)
  • @usr 我认为一般的哲学是返回一些东西比什么都不返回好。即使返回值是多余的,也可能在某些情况下有用,例如其他答案中的链接调用。为什么要排除这样的事情? (2认同)

Sou*_*osh 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.

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

现在谈到原因部分,许多函数都是以这种方式设计的,以使函数调用链接成为可能.这样,您可以调用memmove()另一个函数作为参数,其中复制的值(即指向dest)将具有一定的用途.

例如,您可以编写较短的一个

 puts(memmove(dest_buffer, src_buffer, welcome_message_size));
Run Code Online (Sandbox Code Playgroud)

而不是更长的一个

 memmove(dest_buffer, src_buffer, welcome_message_size);
 puts(dest_buffer);
Run Code Online (Sandbox Code Playgroud)


AnT*_*AnT 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));
Run Code Online (Sandbox Code Playgroud)

即使您不喜欢这种组织代码的方式并且更喜欢通过多个语句执行相同的操作,返回[不必要的]指针值的开销几乎不存在.

甚至可以说,在C99中引入复合文字后,这个习语的价值有所增加.使用复合lterals这个非常成语允许一个人编写相同的代码而不引入一个命名的中间变量

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

some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data));
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为在大多数情况下,命名变量应该是短命的,之后不需要,并且只会混淆命名空间.