ProgrammatieSysteemprogrammeur

Hoe werkt de standaardfunctie memcpy in C, waarvoor wordt deze toegepast en welke valkuilen kunnen zich voordoen bij het gebruik ervan voor het kopiëren van geheugen van verschillende types?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

De functie memcpy uit de standaardbibliotheek (string.h) is bedoeld voor bytegewijze kopie van een geheugengebied van de ene locatie naar de andere. Dit is een universeel hulpmiddel voor het kopiëren van arrays, structs en andere datablokken, wanneer prestaties belangrijk zijn en typeconversies niet nodig zijn.

Achtergrond: memcpy verscheen met de eerste implementatie van de standaardbibliotheek, toen de behoefte aan de verwerking van 'ruwe' geheugengebieden ontstond, bijvoorbeeld voor het werken met bestanden, netwerkpakketten en serialisatie van gegevens. Vergelijkbare functies zijn aanwezig in bijna alle low-level talen.

Probleem: memcpy opereert alleen op bytes, het houdt geen rekening met datatypes, alignment en overlappende geheugengebieden. Fouten bij het opgeven van de grootte of onjuiste gebieden kunnen leiden tot geheugenbeschadiging of onverwachte resultaten. Bovendien veroorzaakt het gebruik van memcpy voor overlappende gebieden onbepaald gedrag.

Oplossing: Gebruik memcpy alleen als je zeker weet:

  • er zijn geen overlappende gebieden;
  • de gekopieerde gegevens worden correct geïnterpreteerd volgens het doelformaat;
  • de grootte van de te kopiëren blokken is correct opgegeven. Gebruik de functie memmove voor overlappende gebieden.

Voorbeeldcode:

#include <string.h> typedef struct { int id; float value; } Item; Item src = {42, 3.14f}; Item dest; memcpy(&dest, &src, sizeof(Item)); // kopieert de struct byte voor byte

Belangrijke kenmerken:

  • Voert geen typeconversie uit
  • Controleert niet op out-of-bounds
  • Kan UB veroorzaken bij overlappende bron- en doelblokken

Misleidende vragen.

Kan memcpy worden gebruikt voor het kopiëren van strings (char)?*

Ja, maar alleen als de lengte precies bekend is. Als de string null-terminated is, worden vaak strcpy of strncpy gebruikt. Als de grootte verwisseld wordt, kan dit leiden tot out-of-bounds geheugen of het verliezen van de terminaal nul.

char src[] = "abc"; char dest[4]; memcpy(dest, src, 4); // Er worden 3 letters + '\0' gekopieerd

Wat gebeurt er bij het kopiëren van structs met niet-standaard alignment of pointers via memcpy?

memcpy houdt geen rekening met semantiek of interne pointers. Als een struct wordt opgeslagen met dynamische velden (bijvoorbeeld char *buf;), wordt alleen het adres gekopieerd, niet de inhoud daarvan. Dit leidt tot wat men noemt 'shallow copy'.

typedef struct { char *buf; } Wrapper; Wrapper src = {malloc(10)}; Wrapper dest; memcpy(&dest, &src, sizeof(Wrapper)); // Alleen de pointer, niet de inhoud

Wat gebeurt er als src en dest in memcpy overlappen?

Het gedrag is niet gedefinieerd door de standaard, dit kan leiden tot dataverlies. Voor overweldigend kopiëren gebruik memmove:

memmove(dest, src, size); // garandeert correcte kopie

Typische fouten en antipatronen

  • Kopiëren met overlapping tussen src en dest
  • Fouten bij het tellen van het aantal bytes (niet sizeof type, maar sizeof pointer)
  • Kopiëren van structs met dynamische of verborgen bronnen (‘shallow copy’ in plaats van diep)

Voorbeeld uit het leven

Negatieve case

Arrays overlappen: memcpy wordt gebruikt om een deel van de array naar rechts te verschuiven, src en dest overlappen gedeeltelijk.

Voordelen:

  • Werkt snel op de meeste platforms

Nadelen:

  • Verlies van een deel van de gegevens, UB, onvoorspelbare bugs

Positieve case

Gebruik memmove voor het verwerken van overlappende gebieden, de hoeveelheid gegevens is precies berekend als het aantal bytes in de oorspronkelijke structuur.

Voordelen:

  • Veilige kopie
  • Leesbaarheid en eenvoud van onderhoud

Nadelen:

  • Ongeveer iets lagere prestaties in vergelijking met memcpy