C中的strtok和strsep有什么区别

有人可以解释一下strtok()strsep()之间有什么区别吗? 它们的优点和缺点是什么? 为什么我会选择一个而不是另一个。

从GNU C Library手册 – 在字符串中查找标记 :

strsepstrtok_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() ,则必须清楚地记录它。

那是因为:

  1. 如果任何调用函数使用strtok()并调用也使用strtok()的函数,则会破坏调用函数。
  2. 如果你的函数调用任何调用strtok()的函数,那将破坏你的函数使用strtok()
  3. 如果您的程序是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()中的其他两个变体。