использованием 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, и строчная буква могут быть добавлены к объявлениям в заголовке."
Если кто-то еще читает это: не используйте strdup() платформы, даже если он доступен, и не тратьте время/усилия с autoconf/automake только для его использования. Серьезно, как это трудно:
char* mystrdup(const char* str)
{
return strcpy(malloc( strlen(str) + 1),str);
}
действительно ли это гарантирует #ifdefs? Проверка компилятора? К. С. И. С.