В чем разница между 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);
Другие вопросы по тегам