Подтвердить что ты не робот

Функция strdup()

Недавно я узнал, что функция strdup(), которой я наслаждался, используя так много в OS X, не является частью ANSI C, а является частью POSIX. Я не хочу переписывать весь свой код, поэтому я думаю, что просто напишу свою собственную функцию strdup(). Это не так сложно, действительно, это просто malloc() и a strcpy(). Во всяком случае, у меня есть функция, но что я делаю, если я пишу эту функцию и свяжу ее с моим кодом, и она уже существует в libc? Будет ли мой компоновщик или компилятор разрешить мне в основном определять мою собственную версию функции или мне нужно дать ей другое имя? Было бы очень удобно, если бы существовал способ повторного использования одного и того же имени, так что если strcpy() существует в пользовательском libc, он может использовать это, но если он не существует в их libc, они могут использовать мою версию вместо этого, как можно меньше изменений кода.

Краткая версия:

a) Что происходит, когда я пишу свою собственную функцию с тем же именем, что и встроенная функция?

b) Что я могу сделать, чтобы избежать плохих вещей, происходящих со мной на платформах, которые не имеют strdup(), не переписывая весь мой код, чтобы не использовать strdup(), что немного утомительно?

4b9b3361

Ответ 1

Обычно вы просто используете #if, чтобы определить нужную функцию, когда под определенным компилятором. Если встроенная библиотека не определяет strdup, нет никаких проблем в ее определении (кроме того, если они будут определять ее в будущем, вам придется ее вынуть.)

// Only define strdup for platforms that are missing it..
#if COMPILER_XYZ || COMPILER_ABC
char *strdup(const char *)
{
   // ....
}
#endif

Ответ 2

вы могли бы просто использовать макрос вроде этого, таким образом вы можете использовать старое имя, но линкер увидит другое имя;

char *my_strdup(const char *s) {
    char *p = malloc(strlen(s) + 1);
    if(p) { strcpy(p, s); }
    return p;
}

/* this goes in whatever header defines my_strdup */
char *my_strdup(const char *s);
#define strdup(x) my_strdup(x)

Ответ 3

Как заметил Роб Кеннеди, лучший способ - проверить внутри своих скриптов здания, если эти функции существуют или нет. Я знаю, что это довольно легко с autoconfig, но, вероятно, с другими инструментами скриптов для построения кросс-платформенных инструментов.

Затем вы просто помещаете в свой файл заголовка:


#ifndef HAVE_STRDUP
# ifdef HAVE__STRDUP
#  define strdup _strdup
# else
#  define strdup my_strdup
# endif
#endif

Если strdup уже существует на целевой платформе, используется версия libc, если не будет использована ваша пользовательская функция my_strdup.

EDIT: Я должен был добавить объяснение, почему это лучше.

Сначала компилятор не связан с существованием функции в libc. Например, возьмите функцию strlcpy. Он присутствует на FreeBSD, но не на Linux (glibc), хотя оба используют gcc по умолчанию. Или что произойдет, если кто-то собирается скомпилировать ваш код с помощью clang?

Во-вторых, проверка платформы (я не знаю, есть ли стандартный способ) будет работать, только если вы явно добавляете для каждого plattform, который хотите поддерживать корректный препроцессор. Поэтому, предполагая, что вы освоили компиляцию своего приложения на OSX и Win32, и вы хотите скомпилировать его сейчас в Linux, вам придется пройти через все условные препроцессоры, чтобы увидеть, работают ли они для Linux. Может быть, вы также хотите поддерживать FreeBSD, OpenBSD и т.д.? Такая же работа снова. С помощью теста в сценариях здания он может компилироваться без дополнительной работы.

Ответ 4

a) Что происходит, когда я пишу свои собственные функции с тем же именем, что и встроенная функция?

Вы не можете переопределить функцию, которая уже существует в заголовочном файле, который вы включаете. Это приведет к ошибке компиляции.

b) Что я могу сделать, чтобы избежать плохих вещей происходит со мной на платформах, которые не имеют strdup() без перезаписи весь мой код, чтобы не использовать strdup(), который просто немного утомительно?

Я бы рекомендовал создать свою собственную оболочку для strdup и заменить все ваши вызовы на использование новой функции-обертки. Например:

char *StringDuplicate(const char *s1)
{
#ifdef POSIX
    return strdup(s1);
#else
    /* Insert your own code here */
#endif
}

Изменение всех ваших вызовов с strdup на StringDuplicate() должно быть простой операцией find-and-replace, что делает ее приемлемым. Логика, специфичная для платформы, будет храниться в одном месте, а не разбросана по всей вашей кодовой базе.

Ответ 5

Также следует избегать создания любого идентификатора (включая функцию), который начинается с str [a-z]. Хотя это не зарезервировано, в разделе 7.26.11 (далее в статьях библиотеки) стандарта C (ISO/IEC 9899: 1999) говорится: "Названия функций, начинающиеся с str, mem или wcs, и строчные буквы могут быть добавлены к объявлениям в заголовке."

Ответ 6

FYI: я никогда не видел среды, которая не определяла strdup().

Ответ 7

Если кто-то еще читает это: Не используйте платформу strdup(), даже если она доступна, и не тратьте время/усилия на использование autoconf/automake только для ее использования. Серьезно, насколько это сложно:

char* mystrdup(const char* str)
{
 return strcpy(malloc( strlen(str) + 1),str);
}

Действительно ли это оправдывает #ifdefs? Проверка компилятора? K.I.S.S.