функция strdup () - PullRequest
       19

функция strdup ()

15 голосов
/ 27 января 2009

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

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

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

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

Ответы [ 7 ]

20 голосов
/ 27 января 2009

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

// Only define strdup for platforms that are missing it..
#if COMPILER_XYZ || COMPILER_ABC
char *strdup(const char *)
{
   // ....
}
#endif
6 голосов
/ 27 января 2009

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

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


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

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

РЕДАКТИРОВАТЬ: Я должен был добавить объяснение, почему это лучше.

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

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

6 голосов
/ 27 января 2009

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

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)
4 голосов
/ 27 января 2009

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

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

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

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

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

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

3 голосов
/ 27 января 2009

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

2 голосов
/ 27 января 2009

К вашему сведению: я никогда лично не видел среду, в которой не определена функция strdup ().

0 голосов
/ 13 июля 2010

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

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

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

...