В чем разница между strtok_r и strtok_s в C? - PullRequest
22 голосов
/ 26 января 2012

Я пытаюсь использовать эту функцию в программе на C, которую нужно компилировать в Linux и Windows. Сначала я попытался использовать strtok_r, но затем, когда я скомпилировал в windows, он пожаловался на то, что функция не существует, и сказал, что он предположит, что это внешняя функция, но затем не удалось. Затем я использовал strtok_s, и он скомпилирован! Тогда я попробовал на Linux, но теперь он жалуется, что есть «неопределенная ссылка на« strtok_s »».

Является ли одна функция только для Windows, а другая функция Linux? Что я могу сделать, чтобы он компилировался на обоих?

Ответы [ 6 ]

33 голосов
/ 26 января 2012

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.

10 голосов
/ 19 сентября 2012

У меня недостаточно репутации, чтобы комментировать другие ответы, поэтому я должен предоставить свой.

1) Для решения этого заявления:

"strtok_s - это безопасная версия strtok для Windows, переполненная буфером. стандартный strtok на окнах потокобезопасен ... "

Это не правда. strtok_s - это потокобезопасная версия для компилятора MSVC. strtok не безопасен для потоков!

2) Для решения этого заявления:

"Это, вероятно, сломалось бы при компиляции на 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-битной цели.

8 голосов
/ 26 января 2012

Обе эти функции - действительно уродливые, не интуитивно понятные идиомы для синтаксического анализа строк, и они обычно не удовлетворяют требованиям вашего конкретного приложения тонкими способами.Более того, для простого strtok в стандартном C. Просто выбросьте их и напишите свой собственный код, чтобы перебрать массив char и разбить его по мере необходимости.strchr, strspn и strcspn могут помочь в этом, или вы можете просто работать с массивом с нуля.

4 голосов
/ 29 мая 2013

Просто чтобы уточнить.strtok является поточно-ориентированным в Windows.strtok использует переменную TLS для поддержки последнего указателя для каждого потока.Однако вы не можете использовать strtok для чередования доступа к более чем одной строке токенов на поток.И strtok_r, и strtok_s решают эту проблему чередования, позволяя пользователю поддерживать контекст с помощью третьего параметра.Надеюсь, это поможет.

4 голосов
/ 26 января 2012

strtok_r - это потокобезопасная версия strtok в системах POSIX.

strtok_s - это безопасная версия strtok с переполнением буфера в Windows.Стандартный strtok на windows является потокобезопасным, поэтому strtok_s должен быть.

0 голосов
/ 15 февраля 2019

MinGW также предопределяет _WIN32, но поддерживает strtok_r, поэтому я не думаю, что стоит проверять макрос _WIN32.Лучше проверить макрос _MSC_VER, который является макросом для Microsoft Visual Studio.

#ifdef _MSC_VER
#define strtok_r strtok_s
#endif

ПРЕДУПРЕЖДЕНИЕ: Microsoft strtok_s и C11 strtok_s совершенно разные!Microsoft strtok_s имеет только 3 параметра, в то время как C11 strtok_s имеет 4 параметра, поэтому это может быть совместимой проблемой в будущем.

Прототип Microsoft strtok_s -

char* strtok_s(char* str, const char* delimiters, char** context);

Прототип C11 strtok_s является

char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);
...