我正在尝试在一个需要能够在Linux和Windows上编译的C程序中使用此函数。起初,我尝试使用strtok_r,但当我在Windows上编译时,它抱怨该函数不存在,并表示它将假定它是一个外部函数,但最后失败了。然后我使用了strtok_s并成功编译了!但是,现在在Linux上尝试时,它抱怨存在“未定义参考‘strtok_s’”。
其中一个是仅适用于Windows的函数,另一个是适用于Linux的函数???我该怎么办才能使其在两个操作系统上都编译通过?
我正在尝试在一个需要能够在Linux和Windows上编译的C程序中使用此函数。起初,我尝试使用strtok_r,但当我在Windows上编译时,它抱怨该函数不存在,并表示它将假定它是一个外部函数,但最后失败了。然后我使用了strtok_s并成功编译了!但是,现在在Linux上尝试时,它抱怨存在“未定义参考‘strtok_s’”。
其中一个是仅适用于Windows的函数,另一个是适用于Linux的函数???我该怎么办才能使其在两个操作系统上都编译通过?
strtok_s
简单来说是 Windows 版本的 strtok_r
,而 strtok_r
则是在其他地方都是标准的。
使一个程序在处理像 strtok_s
/strtok_r
这样的函数时实现可移植性(跨平台兼容),一种常见的方法就是使用预处理器:
#if defined(_WIN32) || defined(_WIN64)
/* We are on Windows */
# define strtok_r strtok_s
#endif
既然原型和功能是相同的,现在您只需要使用strtok_r
。
strtok_r
这样的POSIX接口。使用类似#ifndef HAVE_STRTOK_R
的东西(并在构建脚本中检测它)会更好。 - R.. GitHub STOP HELPING ICE_WIN32
(或_WIN64
)。相反,它定义了__CYGWIN__
和__unix__
。 - Chris Doddstrtok_s
可能是一个好事情:http://en.cppreference.com/w/c/string/byte/strtok。 - Tor Klingberg_WIN32
,但它支持strtok_r
。我认为最好检查_MSC_VER
宏。 - Victor这两个函数都是非常丑陋、难以理解的字符串解析习语,通常会以微妙的方式未能满足您特定应用程序的要求。标准C中的纯 strtok
就更是如此。 抛开它们,并编写自己的代码来遍历 char
数组,并根据需要进行分割。使用strchr
、strspn
和strcspn
可以有所帮助,或者您可以从头开始处理数组。
strtok
的语义可能正是您想要的,唯一的问题是它的状态性(这由strtok_r
和strtok_s
解决)。但我发现,每次我尝试使用它们时,它们都至少有一个方面无法支持我的解析需求,而直接编写代码反而更容易。 - R.. GitHub STOP HELPING ICE由于我没有足够的声望来评论其他答案,所以我必须提供自己的答案。
1)针对这个声明:
"strtok_s是Windows上strtok的缓冲区溢出安全版本。 Windows上的标准strtok是线程安全的..."
这是不正确的。在MSVC编译器中,strtok_s是线程安全的版本。 strtok不是线程安全的!
2)针对这个声明:
"如果在报告自己为Windows但已经定义了POSIX接口(如
strtok_r
)的Cygwin上编译,这可能会破坏它。"
同样不正确。区别在于您使用哪个编译器。当使用微软的Visual C++编译器(MSVC)时,函数为strtok_s
。另一个编译器,例如GNU编译器集合(GCC),可能使用不同的标准库实现,如strtok_r
。在确定要使用哪个函数时,请考虑编译器而不是目标平台。
在我看来,Joachim Pileborg的答案是此页面上最好的答案。不过,它需要进行小的编辑:
#if defined(_WIN32) /* || defined(_WIN64) */
#define strtok_r strtok_s
#endif
_WIN32和_WIN64是由MSVC编译器提供的预定义宏。在编译64位目标时,定义了_WIN64。_WIN32对于32位和64位目标都定义了。这是Microsoft为了向后兼容而做出的妥协。_WIN32被创建来指定Win32 API。现在,你应该考虑使用_WIN32来指定Windows API——它不仅适用于32位目标。
_WIN32
,但它支持 strtok_r
,因此最好检查 _MSC_VER
宏。 - Victor仅作澄清。在Windows中,strtok
是线程安全的。strtok
使用TLS
变量来维护每个线程的最后一个指针。但是,您不能使用strtok
交错访问超过一个标记字符串。 strtok_r
和strtok_s
都通过允许用户通过第三个参数来维护上下文来解决这个交错问题。希望这有所帮助。
strtok_r是POSIX系统上的一个线程安全的strtok版本。
strtok_s是Windows上一个缓冲区溢出安全的strtok版本。Windows上的标准strtok是线程安全的,所以strtok_s也应该是。
strtok_r
是 POSIX 的一部分,已经存在了多年(几十年?) - R.. GitHub STOP HELPING ICEstrtok_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);
。 - VictorMinGW也预定义了_WIN32
,但它支持strtok_r
,因此我认为检查_WIN32
宏不是一个好主意。最好检查_MSC_VER
宏,这是Microsoft Visual Studio的宏。
#ifdef _MSC_VER
#define strtok_r strtok_s
#endif
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);
strtok_s
的原型是:char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);
strtok_r()
是POSIX标准;strtok_s()
是Windows标准。在所有实现中(支持C89),请使用可用的普通strtok()
函数。 - pmg