Exactement ce à quoi cela ressemble, en supposant que vous êtes habitué à la façon abrégée dont C et UNIX attribuent les mots, il duplique les chaînes :-)
En gardant à l'esprit que cela ne fait pas partie de la norme ISO C elle-même (a) (c'est une chose POSIX), cela fait en fait la même chose que le code suivant:
char *strdup(const char *src) {
char *dst = malloc(strlen (src) + 1); // Space for length plus nul
if (dst == NULL) return NULL; // No memory
strcpy(dst, src); // Copy the characters
return dst; // Return the new string
}
En d'autres termes:
Il essaie d'allouer suffisamment de mémoire pour contenir l'ancienne chaîne (plus un caractère «\ 0» pour marquer la fin de la chaîne).
Si l'allocation échoue, il met errno
à ENOMEM
et retourne NULL
immédiatement. La définition de errno
to ENOMEM
est quelque chose qui se malloc
fait dans POSIX, nous n'avons donc pas besoin de le faire explicitement dans notre strdup
. Si vous n'êtes pas conforme à POSIX, ISO C n'exige pas réellement l'existence de ENOMEM
donc je ne l'ai pas inclus ici (b) .
Sinon, l'allocation a fonctionné, nous copions donc l'ancienne chaîne dans la nouvelle chaîne (c) et renvoyons la nouvelle adresse (que l'appelant est responsable de libérer à un moment donné).
Gardez à l'esprit que c'est la définition conceptuelle. Tout écrivain de bibliothèque digne de ce nom peut avoir fourni un code fortement optimisé ciblant le processeur particulier utilisé.
(a) Cependant, les fonctions commençant par str
et une lettre minuscule sont réservées par la norme pour les directions futures. De C11 7.1.3 Reserved identifiers
:
Chaque en-tête déclare ou définit tous les identificateurs répertoriés dans sa sous-clause associée, et * déclare ou définit facultativement les identificateurs répertoriés dans sa future sous-clause de directions de bibliothèque associées. **
Les orientations futures pour string.h
se trouvent dans C11 7.31.13 String handling <string.h>
:
Les noms de fonctions commençant par str
, mem
ou wcs
et une lettre minuscule peuvent être ajoutés aux déclarations dans l'en- <string.h>
tête.
Donc, vous devriez probablement l'appeler autrement si vous voulez être en sécurité.
(b) Le changement serait essentiellement remplacé if (d == NULL) return NULL;
par:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Notez que j'utilise strcpy
pour cela car cela montre clairement l'intention. Dans certaines implémentations, il peut être plus rapide (car vous connaissez déjà la longueur) à utiliser memcpy
, car ils peuvent permettre de transférer les données en plus gros morceaux, ou en parallèle. Ou ce n'est peut-être pas le cas :-) Mantra d'optimisation # 1: "mesurer, ne pas deviner".
Dans tous les cas, si vous décidez de suivre cette voie, vous feriez quelque chose comme:
char *strdup(const char *src) {
size_t len = strlen(src) + 1; // String plus '\0'
char *dst = malloc(len); // Allocate space
if (dst == NULL) return NULL; // No memory
memcpy (dst, src, len); // Copy the block
return dst; // Return the new string
}