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

+2


source to share


3 answers


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

.

+3


source


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.

+6


source


I think the code works because of the differences in string implementation. A VC ++ string implementation needs to make copies when you pass them to a function that could potentially change the string.

0


source







All Articles