ProgrammationProgrammeur système

Comment fonctionne la fonction standard memcpy en C, à quoi sert-elle et quels pièges peuvent survenir lors de son utilisation pour copier la mémoire de différents types ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

La fonction memcpy de la bibliothèque standard (string.h) est destinée à la copie octet par octet d'une zone de mémoire d'un endroit à un autre. C'est un outil universel pour copier des tableaux, des structures et d'autres blocs de données lorsque la performance est importante et qu'aucune conversion de type n'est nécessaire.

Historique de la question : memcpy est apparu avec la première implémentation de la bibliothèque standard, lorsque le besoin de traiter des blocs de mémoire « bruts » s'est fait sentir, par exemple, pour travailler avec des fichiers, des paquets réseau, la sérialisation de données. Des fonctions similaires existent dans presque tous les langages de bas niveau.

Problème : memcpy ne traite que des octets, elle ne se soucie pas des types de données, de l'alignement, ou de la superposition des zones de mémoire. Des erreurs dans la taille spécifiée ou des zones incorrectes peuvent entraîner des corruptions de mémoire ou des résultats inattendus. De plus, l'utilisation de memcpy pour des zones superposées entraîne un comportement indéfini.

Solution : Utilisez memcpy uniquement si vous êtes sûr :

  • qu'il n'y a pas de superposition des zones ;
  • que les données copiées sont correctement interprétées selon le type cible ;
  • que la taille des blocs copiés est spécifiée correctement. Pour les zones superposées, utilisez la fonction memmove.

Exemple de code :

#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // copie la structure octet par octet

Caractéristiques clés :

  • Ne fait pas de conversion de type
  • Ne vérifie pas les dépassements de tableau
  • Peut provoquer un UB en cas de superposition des blocs source et cible

Questions pièges.

Peut-on utiliser memcpy pour copier des chaînes (char) ?*

Oui, seulement si la longueur est exactement connue. Si la chaîne est null-terminated, on utilise souvent strcpy ou strncpy. Si la taille est mélangée, un dépassement de mémoire ou une perte du zéro de fin est possible.

char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // 3 lettres + '\0' sont copiées

Que se passe-t-il lors de la copie de structures avec un alignement non standard ou des pointeurs via memcpy ?

memcpy ne tient compte ni de la sémantique ni des pointeurs internes. Si une structure contient des champs dynamiques (par exemple, char *buf;), seule l'adresse est copiée, et non le contenu. Cela entraîne un « copier superficiel ».

typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // Seulement le champ pointeur, pas le contenu

Que se passera-t-il si src et dest se chevauchent dans memcpy ?

Le comportement n'est pas défini par la norme, une perte de données peut survenir. Pour une copie avec chevauchement, utilisez memmove :

memmove(dest, src, size); // garantit une copie correcte

Erreurs typiques et anti-patterns

  • Copier avec chevauchement entre src et dest
  • Erreurs dans le calcul du nombre d'octets (pas sizeof le type, mais sizeof le pointeur)
  • Copier des structures avec des ressources dynamiques ou cachées (« copie superficielle » au lieu de profonde)

Exemple de la vie réelle

Cas négatif

Les tableaux se chevauchent : memcpy est utilisé pour déplacer une partie du tableau vers la droite, src et dest se chevauchent partiellement.

Avantages :

  • Fonctionne rapidement sur la plupart des plateformes

Inconvénients :

  • Perte de certaines données, UB, bugs imprévisibles

Cas positif

memmove est utilisé pour traiter des zones se chevauchant, le volume de données est clairement calculé en tant que nombre d'octets dans la structure source.

Avantages :

  • Copie sécurisée
  • Lisibilité et facilité de maintenance

Inconvénients :

  • Performance légèrement inférieure par rapport à memcpy