Why does this work with Visual C ++ but not with gcc?
I've been working on a senior project for the past few months, and the main focus of our team's development process has been with the gaps between Visual-C ++ and gcc. (Yes, I know we all should have had the same development environment.) It's over for now, but today I ran into a moderate bug and I wondered if Visual-C ++ is easier for newbies (for example , i) by design.
There is a function in one of my headers that relies on strtok
to slice a string, do some comparisons, and return a string with a similar format. It looks a bit like the following:
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
is notorious for being great for tokenization, but equally good for destroying the original string to be marked. So when I compiled this with gcc and tried to do anything with a
or b
, I got unexpected behavior as the delimiter in use was completely removed in the line. Here's an example in case I am unclear; if i set a = "Jim,Bob,Mary"
and b="Grace,Soo,Hyun"
, they will be defined as a="JimBobMary"
and b="GraceSooHyun"
instead of staying the same as i wanted.
However, when I compiled this in Visual C ++, I returned the original lines and the program ran fine.
I tried to dynamically allocate memory to strings and copy them the "standard" way, but the only way that worked was using malloc()
and free()
which I hear is not recommended in C ++. While I'm interested, the real question I have is, why did the program work when compiled in VC ++, but not with gcc?
(This is one of many conflicts I've experienced when trying to make cross-platform code.)
Thanks in advance!
-Carlos Nunez
source to share
Tokens are automatically null-substituted by function strtok
. This is not something you can do with persistent data.
To make your code safe and cross-platform use boost::tokenizer
.
source to share
This is an example of undefined behavior. You are passing the result string::c_str()
, a const char*
, to strtok, which it accepts char*
. By modifying the data content of the std :: string, you are invoking undefined behavior (you should receive warnings for this if you are not casting).
When do you check the value of a and b? In get_string or mainly? get_string is passed in copies of a and b, so strtok most likely doesn't change the originals in main. However, it can, since you are invoking undefined behavior.
The correct way to do this is with malloc / free or new [] / delete []. You are using a C function, so you are already guilty of the same crime as you are using malloc / free. A relatively elegant but safe way to approach this:
char *ap = strdup(a.c_str());
const char *a_ch = strtok(ap, ",");
/* do whatever it is you do */
free(ap);
Also remember that strtok uses global state, so it won't work well with streams.
source to share