为什么这适用于Visual C ++,但不适用于gcc?

时间:2010-04-12 04:07:07

标签: c++ string gcc

我过去几个月一直在做一个高级项目,我们团队开发过程中的一个主要问题是处理Visual-C ++和gcc之间的分歧。 (是的,我知道我们都应该拥有相同的开发环境。)事情就此完成了,但是我今天碰到了一个温和的bug,让我想知道Visual-C ++对于新手是否更容易(像我一样)按设计。

在我的一个标题中,有一个函数依赖于strtok来剪切一个字符串,进行一些比较并返回一个类似格式的字符串。它的工作原理如下:

int main()  
{  
    string a, b, c;  
    //Do stuff with a and b.  
    c = get_string(a,b);  
}   

string get_string(string a, string b) { const char * a_ch, b_ch; a_ch = strtok(a.c_str(),","); b_ch = strtok(b.c_str(),","); }

strtok因为在标记化方面表现出色而臭名昭着,但在摧毁原始字符串以进行标记化方面同样出色。因此,当我使用gcc编译它并试图对ab做任何事情时,我得到了意外的行为,因为在字符串中完全删除了使用的分隔符。这是一个我不清楚的例子;如果我设置a = "Jim,Bob,Mary"b="Grace,Soo,Hyun",则会将其定义为a="JimBobMary"b="GraceSooHyun",而不是像我想要的那样保持不变。

然而,当我在Visual C ++下编译它时,我找回原始字符串并且程序执行正常。

我尝试动态地为字符串分配内存并以“标准”方式复制它们,但唯一有效的方法是使用malloc()free(),我听说在C ++中不鼓励这样做。虽然我对此感到好奇,但我真正的问题是:为什么程序在用VC ++编译时能够工作,而不是用gcc编写?

(这是我在尝试使代码跨平台时遇到的众多冲突之一。)

提前致谢!

-Carlos Nunez

3 个答案:

答案 0 :(得分:6)

这是未定义行为的示例。您将string::c_str()的结果const char*传递给strtok,其中char*char *ap = strdup(a.c_str()); const char *a_ch = strtok(ap, ","); /* do whatever it is you do */ free(ap); 。通过修改std :: string数据的内容,您将调用未定义的行为(除非您正在进行转换,否则应该收到警告)。

你什么时候检查a和b的值?在get_string中,还是在main中? get_string传递了a和b的副本,因此strtok很可能不会改变main中的原件。但是,它可以,因为您正在调用未定义的行为。

执行此操作的“正确方法”是使用malloc / free或new [] / delete []。你正在使用C函数,所以你已经犯了与使用malloc / free相同的犯罪行为。一种相对优雅但安全的方法是:

{{1}}

另外请记住,strtok使用全局状态,因此它不能很好地与线程一起使用。

答案 1 :(得分:3)

标记将由函数strtok自动替换为空字符。这不是你可以用常数数据做的事情。

为了使您的代码安全且跨平台,请考虑使用boost::tokenizer

答案 2 :(得分:0)

我认为代码正在运行,因为字符串实现存在差异。将VC ++字符串实现传递给可能修改字符串的函数时,VC ++字符串实现必须进行复制。