Dokładnie tak, jak to brzmi, zakładając, że przyzwyczaiłeś się do skróconego sposobu, w jaki C i UNIX przypisują słowa, powiela ciągi :-)
Pamiętając, że tak naprawdę nie jest częścią samego standardu ISO C (a) (jest to kwestia POSIX), skutecznie robi to samo, co następujący kod:
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
}
Innymi słowy:
Próbuje przydzielić wystarczającą ilość pamięci, aby pomieścić stary ciąg (plus znak „\ 0”, aby zaznaczyć koniec łańcucha).
Jeśli przydział nie powiodła się, to ustawia errnosię ENOMEMi powraca NULLnatychmiast. Ustawienie od errnocelu ENOMEMjest coś mallocnie w POSIX, więc nie trzeba jawnie robić w naszym strdup. Jeśli jesteś nie POSIX zgodne, ISO C faktycznie nie wprowadzały istnienie ENOMEMwięc nie obejmowały że tutaj (b) .
W przeciwnym razie przydział zadziałał, więc kopiujemy stary ciąg do nowego ciągu (c) i zwracamy nowy adres (który w pewnym momencie odpowiedzialny jest za zwolnienie).
Pamiętaj, że to jest definicja koncepcyjna. Każdy pisarz biblioteki warty swojej pensji mógł dostarczyć wysoce zoptymalizowany kod skierowany do konkretnego używanego procesora.
(a) Jednak funkcje rozpoczynające się strod małej litery są rezerwowane przez standard dla przyszłych kierunków. Od C11 7.1.3 Reserved identifiers:
Każdy nagłówek deklaruje lub definiuje wszystkie identyfikatory wymienione w powiązanej podpunkcie, a * opcjonalnie deklaruje lub definiuje identyfikatory wymienione w powiązanej przyszłej podpunkcie kierunków bibliotek. **
Przyszłe kierunki dla string.hmożna znaleźć w C11 7.31.13 String handling <string.h>:
Nazwy funkcji rozpoczynające się od str, memlub wcsmałą literą mogą być dodawane do deklaracji w <string.h>nagłówku.
Prawdopodobnie powinieneś to nazwać czymś innym, jeśli chcesz być bezpieczny.
(b) Zmiana polegałaby zasadniczo na if (d == NULL) return NULL;:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Zauważ, że używam strcpydo tego, ponieważ wyraźnie pokazuje to zamiar. W niektórych implementacjach użycie może być szybsze (ponieważ znasz już długość) memcpy, ponieważ mogą one umożliwiać przesyłanie danych w większych porcjach lub równolegle. A może nie :-) Mantra optymalizacji nr 1: „mierz, nie zgaduj”.
W każdym razie, jeśli zdecydujesz się wybrać tę trasę, zrobiłbyś coś takiego:
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
}