Est-ce que memcpy ou memmove peut renvoyer un pointeur différent de celui de dest?

La fonction memmove est définie comme suit:

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

Dans la page de manuel Linux, il est écrit:

VALEUR DE RETOUR
La fonction memmove () renvoie un pointeur sur dest.

Pourquoi la fonction n’est-elle pas simplement définie comme void memmove(…) lorsqu’elle renvoie toujours l’un des parameters d’entrée? La valeur de retour peut-elle être différente de dest ?

Ou la valeur de retour est-elle vraiment toujours la même et il suffit de la composer de manière créative?

memmove ne retournera jamais rien d’autre que dest .

Le retour de dest , par opposition à la création de memmove void, est utile lorsque le premier argument est une expression calculée, car il évite de calculer la même valeur initiale et de la stocker dans une variable. Cela vous permet de faire en une seule ligne

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

ce que vous devriez faire autrement sur deux lignes:

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

Conformément à C11 , chapitre §7.24.2.1 et §7.24.2.2

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

[…] La fonction memcpy renvoie la valeur de s1 .

et,

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

[…] La fonction memmove renvoie la valeur de s1 .

Ainsi, les fonctions renverront toujours le pointeur vers le tampon de destination, ce qui est prévu.

Maintenant que la partie pourquoi , de nombreuses fonctions sont conçues de cette manière pour rendre possible le chaînage des appels de fonctions. De cette façon, vous pouvez appeler memmove() en tant qu’argument vers une autre fonction, où la valeur copiée ( c.-à-d. Le pointeur vers la dest ) va être utile.

Par exemple, vous pouvez écrire le plus court

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

au lieu de la plus longue

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

L’idée de renvoyer la valeur exacte de l’un des arguments (de type pointeur) existe afin de prendre en charge les appels de fonction “chaînés” (voir également strcpy , strcat etc.). Il vous permet d’écrire du code répétitif sous la forme d’une seule expression au lieu de le diviser en plusieurs instructions. Par exemple

 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)); 

Même si vous n’aimez pas ce style d’organisation du code et que vous préférez faire la même chose avec plusieurs instructions, le retour d’une valeur de pointeur [inutile] est pratiquement inexistant.

On peut même dire que la valeur de cet idiome a légèrement augmenté après l’introduction des littéraux composés en C99. Avec les lterals composés, cet idiome permet d’écrire le même code sans introduire de variable intermédiaire nommée

 printf("%s\n", strcat(strcat(strcpy((char [1024]) { 0 }, "Hello"), " "), "World!")); some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data)); 

ce qui est logique car dans la plupart des cas, la variable nommée est supposée être de courte durée, n’est pas nécessaire par la suite, et ne fait qu’encombrer l’espace de nommage.