C中的strtok和strsep有什么区别
有人可以解释一下strtok()
和strsep()
之间有什么区别吗? 它们的优点和缺点是什么? 为什么我会选择一个而不是另一个。
从GNU C Library手册 – 在字符串中查找标记 :
strsep
和strtok_r
之间的一个区别是,如果输入字符串在一行中包含来自分隔符的多个字符,则strsep
分隔符中的每对字符返回一个空字符串。 这意味着程序通常应该在处理之前测试strsep
返回空字符串。
strtok()
和strsep()
之间的一个主要区别是strtok()
是标准化的(通过C标准,因此也是POSIX)但是strsep()
没有标准化(通过C或POSIX;它在GNU C中可用)图书馆,起源于BSD)。 因此,可移植代码比strsep()
更可能使用strtok()
strsep()
。
另一个区别是对不同字符串的strsep()
函数的调用可以交错,而你不能用strtok()
(尽管你可以使用strtok_r()
)。 因此,在库中使用strsep()
不会意外破坏其他代码,而在库函数中使用strtok()
必须记录,因为使用strtok()
其他代码同时无法调用库函数。
kernel.org上的strsep()
手册页说:
引入strsep()函数作为strtok(3)的替代,因为后者无法处理空字段。
因此,另一个主要区别是GeorgeGaál在他的回答中强调的那个; strtok()
允许在单个标记之间使用多个分隔符,而strsep()
期望标记之间有单个分隔符,并将相邻分隔符解释为空标记。
strsep()
和strtok()
修改了它们的输入字符串,并且都strsep()
您识别标记令牌末尾的分隔符(因为在令牌结束后在分隔符上写入NUL '\0'
)。
什么时候使用它们?
- 当你想要空令牌而不是在令牌之间允许多个分隔符时,以及当你不介意可移植性时,你会使用
strsep()
。 - 如果要在令牌之间允许多个分隔符并且不想要空标记(并且POSIX对您来说足够便携
strtok_r()
,则可以使用strtok_r()
)。 - 如果有人威胁你的生命,你只会使用
strtok()
。 而你只能用它足够长的时间让你摆脱危及生命的境地; 然后你会再次放弃使用它。 它有毒; 不要使用它。 编写自己的strtok_r()
或strsep()
比使用strtok()
更好。
为什么strtok()
有毒?
如果在库函数中使用, strtok()
函数是有毒的。 如果库函数使用strtok()
,则必须清楚地记录它。
那是因为:
- 如果任何调用函数使用
strtok()
并调用也使用strtok()
的函数,则会破坏调用函数。 - 如果你的函数调用任何调用
strtok()
的函数,那将破坏你的函数使用strtok()
。 - 如果您的程序是multithreading的,那么在一系列
strtok()
调用中,最多只有一个线程可以在任何给定时间使用strtok()
。
这个问题的根源是调用之间保存的状态,它允许strtok()
在它停止的地方继续。 除了“不要使用strtok()
”之外,没有合理的方法来解决问题。
- 如果可用,您可以使用
strsep()
。 - 您可以使用POSIX的
strtok_r()
如果可用)。 - 您可以使用Microsoft的
strtok_s()
如果可用)。 - 名义上,您可以使用ISO / IEC 9899:2011附件K.3.7.3.1函数
strtok_s()
,但其界面与strtok_r()
和Microsoft的strtok_s()
。
BSD strsep()
:
char *strsep(char **stringp, const char *delim);
POSIX strtok_r()
:
char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state);
Microsoft strtok_s()
:
char *strtok_s(char *strToken, const char *strDelimit, char **context);
附件K strtok_s()
:
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);
请注意,这有4个参数,而不是strtok()
中的其他两个变体。