Точно так же, как это звучит, если вы привыкли к сокращенному способу, которым C и UNIX назначают слова, он дублирует строки :-)
Помня, что это на самом деле не является частью самого стандарта ISO C (а) (это POSIX), он фактически делает то же самое, что и следующий код:
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
}
Другими словами:
Он пытается выделить достаточно памяти для хранения старой строки (плюс символ '\ 0', чтобы отметить конец строки).
Если распределение не удалось, он устанавливает errno
в ENOMEM
и возвращается NULL
сразу. Установка errno
to ENOMEM
это что-то malloc
делает в POSIX, поэтому нам не нужно явно делать это в нашем strdup
. Если вы не POSIX-совместимый, ISO C на самом деле не требует наличия, ENOMEM
поэтому я не включил это здесь (б) .
В противном случае распределение сработало, поэтому мы копируем старую строку в новую строку (c) и возвращаем новый адрес (который вызывающий отвечает за освобождение в некоторый момент).
Имейте в виду, что это концептуальное определение. Любой писатель библиотеки, достойный своей зарплаты, мог предоставить сильно оптимизированный код, предназначенный для конкретного используемого процессора.
(a) Однако функции, начинающиеся с str
буквы в нижнем регистре, зарезервированы стандартом для будущих направлений. От C11 7.1.3 Reserved identifiers
:
Каждый заголовок объявляет или определяет все идентификаторы, перечисленные в соответствующем подпункте, а * необязательно объявляет или определяет идентификаторы, перечисленные в соответствующем подпункте будущих направлений библиотеки. **
Будущие направления для string.h
можно найти в C11 7.31.13 String handling <string.h>
:
Имена функций, начинающиеся с str
, mem
или wcs
строчная буква могут быть добавлены в объявления в <string.h>
заголовке.
Так что вы, вероятно, должны называть это чем-то другим, если хотите быть в безопасности.
(b) Изменение в основном будет заменено следующим if (d == NULL) return NULL;
:
if (d == NULL) {
errno = ENOMEM;
return NULL;
}
(c) Обратите внимание, что я использую strcpy
для этого, поскольку это ясно показывает намерение. В некоторых реализациях может быть быстрее (так как вы уже знаете длину) использовать memcpy
, поскольку они могут позволять передавать данные большими кусками или параллельно. Или не может :-) Оптимизация мантра № 1: «измерить, не угадать».
В любом случае, если вы решите пойти по этому пути, вы должны сделать что-то вроде:
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
}