C中的strtok_r和strtok_s有什么区别?

pet*_*aya 22 c linux windows compiler-errors strtok

我正在尝试在需要能够在Linux和Windows中编译的C程序中使用此函数.起初我尝试使用strtok_r,但是当我在windows上编译时,它抱怨函数不存在并且说它会假设它是一个外部函数,但后来失败了.然后我用strtok_s编译了!然后我尝试在Linux上,但现在它抱怨有一个"未定义的引用'strtok_s'".

是一个Windows唯一的功能,另一个是Linux功能??? 我能做些什么才能在两者上编译?

Som*_*ude 34

strtok_s只是Windows版本strtok_r在其他地方都是标准版本.

一个(我会想到的常见的)方法是使程序可移植到像strtok_s/ 这样的函数strtok_r是使用预处理器:

#if defined(_WIN32) || defined(_WIN64)
/* We are on Windows */
# define strtok_r strtok_s
#endif
Run Code Online (Sandbox Code Playgroud)

由于原型和功能相同,您现在只能使用strtok_r.

  • @R ..:cygwin实际上并没有正确地定义`_WIN32`(或`_WIN64`) - 它通常用于识别非unix的代码.Cygwin定义了`__CYGWIN__`和`__ unix__` (5认同)
  • 可能很高兴知道C11中还有一个带有完全不同签名的`strtok_s`:http://en.cppreference.com/w/c/string/byte/strtok (2认同)
  • @ChrisDodd MinGW 上仍然存在问题。MinGW 预定义了 `_WIN32` 但它支持 `strtok_r`。我认为最好检查`_MSC_VER` 宏。 (2认同)

BeR*_*l82 10

我没有足够的声誉来评论其他答案,所以我必须提供自己的答案.

要解决这个问题:

"strtok_s是Windows上strtok的缓冲区溢出安全版本.Windows上的标准strtok是线程安全的......"

这不是真的.strtok_s是MSVC编译器的线程安全版本.strtok不是线程安全的!

要解决这个问题:

"如果在cygwin上进行编译,这可能会破坏,cygwin将自己报告为窗口但是已经定义了像strtok_r这样的posix接口."

再次,不是真的.区别在于您使用的编译器.使用Microsoft的Visual C++编译器MSVC时,函数是strtok_s.另一个编译器,例如GNU Compiler Collection,GCC,可以使用不同的标准库实现,例如strtok_r.在识别要使用的功能时,请考虑编译器,而不是目标平台.

在我看来,Joachim Pileborg的答案是本页最好的答案.但是,它需要一个小编辑:

#if defined(_WIN32) /* || defined(_WIN64) */
#define strtok_r strtok_s
#endif
Run Code Online (Sandbox Code Playgroud)

_WIN32和_WIN64都是MSVC编译器提供的预定义宏.编译64位目标时定义_WIN64._WIN32是为32位和64位目标定义的.这是Microsoft为向后兼容性所做的妥协.创建_WIN32以指定Win32 API.现在您应该考虑_WIN32来指定Windows API - 它不是特定于32位目标.

  • 关于第一点,您错了:strtok **在 Windows 上是**线程安全的,因为两个不同的线程可以在同一进程中安全地使用该函数,即使 strtok 有 [another answer](http: //stackoverflow.com/a/16821026/656988)@JameyKirby。 (2认同)

R..*_*R.. 8

这两个函数都是用于解析字符串的非常丑陋,不直观的习惯用法,并且通常无法以微妙的方式满足您的特定应用程序的要求.甚至更多的strtok是标准C中的普通.只需将它们抛出并编写自己的代码来迭代char数组并根据需要将其分解.strchr,strspn并且strcspn可以帮助您做到这一点,或者您可以从头开始在阵列上工作.

  • -1:为了解析一个已被读入临时缓冲区的字符串,你想要丢弃分隔符,你只希望字符串有效,直到你完成解析,strtok正是你想要的,strtok_r/strtok_s好多了因为它是可重入的. (7认同)
  • 请注意,肯定在*某些*情况下,`strtok`语义正是你想要的,唯一的问题是有状态(`strtok_r`和`strtok_s`修复).我只是发现每次我尝试使用它们时,至少有一个方面是我不支持我的解析需求,并且最终更容易直接编写代码. (4认同)
  • (1)分隔符char被覆盖/丢失,因此除非您只有一个可能的分隔符,否则您将丢失信息.(2)多个连续的分隔符被视为一个,如果你的分隔符是空格,但是如果它是一个逗号,则是有意义的,例如.. (3认同)
  • 你能解释一下为什么这些功能不好吗?对我来说,这似乎比逐个字符和搜索事物更直观。 (2认同)

小智 7

只是为了澄清。strtok在 Windows 中是线程安全的。strtok使用一个TLS变量来维护每个线程的最后一个指针。但是,您不能使用strtok交错访问每个线程多个令牌字符串。strtok_r并且strtok_s两者都通过允许用户通过第三个参数维护上下文来解决这个交织问题。希望这可以帮助。


Mar*_*ett 5

strtok_r 是 POSIX 系统上 strtok 的线程安全版本

strtok_s是 Windows 上 strtok 的缓冲区溢出安全版本。Windows 上的标准 strtok 是线程安全的,所以 strtok_s 应该是。

  • @AlexanderRiccio Microsoft `strtok_s` 和 C11 `strtok_s` 完全不同!Microsoft `strtok_s` 只有 3 个参数,而 C11 `strtok_s` 有 4 个参数。微软`strtok_s`的原型是`char* strtok_s(char* str, const char* delimiters, char** context);`而C11 `strtok_s`的原型是`char *strtok_s(char *restrict str, rsize_t *限制 strmax, const char *restrict delim, char **restrict ptr);`。 (2认同)