Почему strtok () считается небезопасным?
какая особенность(ы)strtok
небезопасно (с точки зрения переполнения буфера), что мне нужно остерегаться?
что немного странно для меня это strtok_s
(что является" безопасным") в Visual C++ имеет дополнительный параметр" context", но похоже, что это то же самое и в других отношениях... это одно и то же или на самом деле другое?
4 ответов
в соответствии с разделом strtok_s документ:
6.7.3.1 функция strtok_s функция strtok_s устраняет две проблемы в функции strtok:
- новый параметр s1max предотвращает хранение strtok_s за пределами строки лексемы. (Строка была разделена на жетоны и вход и выход функции since strtok_s хранит нулевые символы в строка.)
- A новый параметр ptr устраняет статическое внутреннее состояние, которое предотвращает повторный вход strtok (Подпункт 1.1.12). (ISO / IEC 9899 функция wcstok и ISO / IEC 9945 (POSIX) функция strtok_r исправить это проблема тож.)
в этом нет ничего опасного. Нужно просто понять как это работает и как это использовать. После написания кода и модульного теста требуется всего несколько дополнительных минут для повторного запуска модульного теста с valgrind, чтобы убедиться, что вы работаете с границами памяти. На man-странице говорит все это:
ошибки
будьте осторожны при использовании этих функций. Если вы используете их, обратите внимание, что:
- эти функции измените их первый аргумент.
- эти функции нельзя использовать в постоянных строках.
- идентичность разделяющего символа теряется.
- на
strtok()
функция использует статический буфер при разборе, поэтому он не является потокобезопасным. Использоватьstrtok_r()
если это имеет значение для вас.
strtok безопасен в Visual C++ (но нигде больше), поскольку он использует локальное хранилище потоков для сохранения своего состояния между вызовами. Во всем остальном глобальная переменная используется для сохранения состояния strtok ().
однако даже в VC++, где strtok является потокобезопасным, это все еще немного странно - вы не можете использовать strtok () s на разных строках в одном потоке одновременно. Например, это не будет работать хорошо:
token = strtok( string, seps );
while(token)
{
printf("token=%s\n", token)
token2 = strtok(string2, seps);
while(token2)
{
printf("token2=%s", token2);
token2 = strtok( NULL, seps );
}
token = strtok( NULL, seps );
}
причина, почему это не будет работать хорошо только для каждого потока одно состояние можно сохранить в локальном хранилище потоков, и здесь потребуется 2 состояния - для первой строки и для второй строки. Поэтому, хотя strtok является потокобезопасным с VC++, он не является реентерабельным.
то, что strtok_s (или strtok_r везде) предоставляет - явное состояние, и с этим strtok становится reentrant.
Если у вас нет правильно завершенной строки null; вы окажетесь в переполнении буфера. Также обратите внимание (это то, что я узнал на горьком опыте) strtok, похоже, не заботится о внутренних строках. Т. е. наличие "hello"/"world"будет анализировать"hello"/"world", тогда как "hello / world"будет анализировать " hello world". Обратите внимание, что он разбивается на / и игнорирует тот факт, что он находится в круглой скобке.