Почему это работает с Visual C ++, но не с gcc? - PullRequest
2 голосов
/ 12 апреля 2010

Последние несколько месяцев я работаю над старшим проектом, и основным камнем преткновения в процессе разработки нашей команды стало устранение разногласий между Visual-C ++ и gcc. (Да, я знаю, что у всех нас должна была быть одна и та же среда разработки.) На данный момент все готово, но я наткнулся на небольшую ошибку, которая заставила меня задуматься, проще ли Visual-C ++ для новичков (таких как я) по конструкции.

В одном из моих заголовков есть функция, которая опирается на strtok, чтобы разрезать строку, сделать несколько сравнений и вернуть строку с аналогичным форматом. Это работает примерно так:

int main()  
{  
    string a, b, c;  
    //Do stuff with a and b.  
    c = get_string(a,b);  
}   <br /><br />
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 и попытался сделать что-нибудь с a или b, я получил неожиданное поведение, так как используемый разделитель был полностью удален в строке. Вот пример на случай, если мне неясно; если я установлю a = "Jim,Bob,Mary" и b="Grace,Soo,Hyun", они будут определены как a="JimBobMary" и b="GraceSooHyun" вместо того, чтобы оставаться такими же, как я хотел.

Однако, когда я скомпилировал это в Visual C ++, я вернул исходные строки, и программа работала нормально.

Я попытался динамически выделить память для строк и скопировать их «стандартным» способом, но единственный работающий способ - это использование malloc() и free(), что, как я слышал, не приветствуется в C ++. Хотя мне любопытно, реальный вопрос, который у меня возникает, заключается в следующем: почему программа работала при компиляции в VC ++, а не с gcc?

(Это один из многих конфликтов, с которыми я столкнулся при попытке сделать код кроссплатформенным.)

Заранее спасибо!

-Карлос Нуньес

Ответы [ 3 ]

6 голосов
/ 12 апреля 2010

Это пример неопределенного поведения. Вы передаете результат string::c_str(), const char*, в strtok, который занимает char*. Изменяя содержимое данных std :: string, вы вызываете неопределенное поведение (вы должны получать предупреждения об этом, если вы не читаете).

Когда вы проверяете значения a и b? В get_string или в main? get_string передается копии a и b, поэтому strtok, скорее всего, не будет изменять оригиналы в main. Однако это может произойти, поскольку вы вызываете неопределенное поведение.

«Правильный способ» сделать это - использовать malloc / free или new [] / delete []. Вы используете функцию C, поэтому вы уже виновны в том же преступлении, что и при использовании malloc / free. Относительно элегантный, но безопасный способ подойти к этому:

char *ap = strdup(a.c_str());
const char *a_ch = strtok(ap, ",");
/* do whatever it is you do */
free(ap);

Также имейте в виду, что strtok использует глобальное состояние, поэтому он не будет хорошо работать с потоками.

3 голосов
/ 12 апреля 2010

Жетоны будут автоматически заменены нулевым символом функцией strtok. Это не то, что вы можете сделать с постоянными данными.

Чтобы сделать ваш код безопасным и межплатформенным, рассмотрите возможность использования boost::tokenizer.

0 голосов
/ 12 апреля 2010

Я думаю, что код работает из-за различий в реализации строк. Реализация строки VC ++ должна делать копии, когда вы передаете их функции, которая потенциально может изменить строку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...