использованием strdup() функция

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

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

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

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

7 ответов


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

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

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

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)

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

тогда вы просто поместите в свой заголовочный файл:


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

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

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

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

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


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

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

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

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

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

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


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


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


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

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

действительно ли это гарантирует #ifdefs? Проверка компилятора? К. С. И. С.