В чем разница между strtok_r и strtok_s в C?
Я пытаюсь использовать эту функцию в программе на C, которая должна компилироваться в Linux и Windows. Сначала я попытался использовать strtok_r, но затем, когда я скомпилировал в Windows, он пожаловался на то, что функция не существует, и сказал, что он предположит, что это внешняя функция, но затем не удалось. Затем я использовал strtok_s, и он скомпилирован! Тогда я попробовал на Linux, но теперь он жалуется, что есть "неопределенная ссылка на" strtok_s "".
Является ли одна функция только для Windows, а другая функция Linux? Что я могу сделать, чтобы он компилировался на обоих?
5 ответов
Обе эти функции - действительно уродливые, не интуитивно понятные идиомы для разбора строк, и они обычно не удовлетворяют требованиям вашего конкретного приложения тонкими способами. Еще больше для равнины strtok
в стандартном C. Просто выбросьте их и напишите свой собственный код, чтобы перебрать char
массив и разбить его по мере необходимости. strchr
, strspn
, а также strcspn
может быть полезным в этом, или вы можете просто работать с массива с нуля.
strtok_s
это просто версия для Windows strtok_r
который является стандартным везде
Один (я бы подумал) способ сделать программу переносимой, когда дело доходит до таких функций, как strtok_s
/strtok_r
это использовать препроцессор:
#if defined(_WIN32) || defined(_WIN64)
/* We are on Windows */
# define strtok_r strtok_s
#endif
Поскольку прототипы и функциональность одинаковы, теперь вы можете использовать только strtok_r
,
У меня недостаточно репутации, чтобы комментировать другие ответы, поэтому я должен предоставить свой собственный.
Для решения этого заявления:
"strtok_s - это безопасная версия strtok для Windows, защищенная от переполнения буфера. Стандартный strtok для Windows является поточно-ориентированным..."
Это неправда. strtok_s - это потокобезопасная версия для компилятора MSVC. strtok не является поточно-ориентированным!
Для решения этого заявления:
"Это, вероятно, сломалось бы при компиляции на cygwin, который сообщает о себе как о windows, но имеет уже определенные интерфейсы posix, такие как strtok_r"
Опять не правда. Разница в том, какой компилятор вы используете. При использовании компилятора Microsoft Visual C++ MSVC используется функция strtok_s. Другой компилятор, такой как коллекция компиляторов GNU, GCC, может использовать другую реализацию стандартной библиотеки, такую как strtok_r. При определении того, какую функцию использовать, думайте о компиляторе, а не целевой платформе.
На мой взгляд, ответ Йоахима Пилеборга - лучший на этой странице. Однако, это требует небольшого редактирования:
#if defined(_WIN32) /* || defined(_WIN64) */
#define strtok_r strtok_s
#endif
И _WIN32, и _WIN64 являются предопределенными макросами, предоставляемыми компилятором MSVC. _WIN64 определяется при компиляции 64-битной цели. _WIN32 определен для 32- и 64-битных целей. Это компромисс, который Microsoft сделала для обратной совместимости. _WIN32 был создан для указания Win32 API. Теперь вы должны рассмотреть _WIN32, чтобы указать Windows API - это не относится к 32-битной цели.
Просто для ясности. strtok является поточно-ориентированным в Windows. strtok использует переменную TLS для поддержки последнего указателя для каждого потока. Однако вы не можете использовать strtok для чередования доступа к более чем одной строке токена на поток. И strtok_r, и strtok_s решают эту проблему чередования, позволяя пользователю поддерживать контекст с помощью третьего параметра. Надеюсь это поможет.
strtok_r - это потокобезопасная версия strtok в системах POSIX
strtok_s - это безопасная версия strtok для Windows, переполненная буфером. Стандартный strtok на windows является поточно-ориентированным, поэтому strtok_s должен быть.
MinGW также предопределяет _WIN32
но это поддерживает strtok_r
так что я не думаю, что это хорошая идея проверить _WIN32
макро. Лучше проверить _MSC_VER
макрос, который является макросом для Microsoft Visual Studio.
#ifdef _MSC_VER
#define strtok_r strtok_s
#endif
ВНИМАНИЕ: Microsoft strtok_s
и С11 strtok_s
совершенно разные! Microsoft strtok_s
имеет только 3 параметра, в то время как C11 strtok_s
имеет 4 параметра, так что это может быть совместимой проблемой в будущем.
Прототип Microsoft strtok_s
является
char* strtok_s(char* str, const char* delimiters, char** context);
Прототип С11 strtok_s
является
char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);