На что обратить внимание при преобразовании std :: string в char * для функции C? - PullRequest
12 голосов
/ 12 апреля 2011

Я прочитал много постов, задающих вопрос о том, как преобразовать C ++ std::string или const std::string& в char*, чтобы передать его в функцию C, и, похоже, есть несколько предостережений относительно этого , Нужно остерегаться смежности струн и многих других вещей. Дело в том, что я никогда не понимал все моменты, о которых нужно знать, и почему ?

Я задавался вопросом, может ли кто-то суммировать предостережения и недостатки, связанные с преобразованием из std::string в char*, которое необходимо для перехода к функции C?

Это когда std::string является ссылкой const и когда это просто неконстантная ссылка, и когда функция C изменит char* и когда она не изменит ее.

Ответы [ 5 ]

11 голосов
/ 12 апреля 2011

Во-первых, ссылка на констант или значение ничего не меняет.

Затем вы должны рассмотреть, что ожидает функция. Там разные вещи, которые функция может сделать с char* или char const* --- оригинальные версии memcpy, для Например, использовали эти типы, и возможно, что есть еще такой код вокруг. Это, надеюсь, редко, и в следующем, Я предполагаю, что char* в функции C относится к '\0' завершенные строки.

Если функция C принимает char const*, вы можете передать ей результаты std::string::c_str(); если это займет char*, это зависит. Если это займет char* просто потому, что он датируется до const дней C, и на самом деле, это ничего не меняет, std::string::c_str(), за которым следует const_cast is подходящее. Если функция C использует char* как выход Параметр, однако, становится сложнее. Я лично предпочитаю объявить буфер char[], передать его, а затем преобразование результатов в std::string, но все известные реализации std::string используют непрерывный буфер и следующая версия стандарта потребует этого, поэтому правильно сначала определим размер std::string (используя std::string::resize(), затем прохождение &s[0], а затем переразмер строки на полученную длину (определяется использование strlen(s.c_str()), если необходимо) также может быть использовано.

Наконец (но это также проблема для программ на C, использующих char[]), вы должны рассмотреть любые проблемы на всю жизнь. Наиболее функции, принимающие char* или char const*, просто используют указатель, и забудьте об этом, но если функция сохраняет указатель где-то, для дальнейшего использования, строковый объект должен жить как минимум так долго, и его размер не должен изменяться в течение этого периода. (Опять же, в таких случаях я предпочитаю использовать char[].)

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

По сути, важны три момента:

  • В соответствии с действующим стандартом, std::string фактически не гарантирует использование смежного хранилища (насколько я знаюэто связано с изменением).Но на самом деле, все текущие реализации, вероятно, используют непрерывное хранилище в любом случае.По этой причине c_str()data()) может на самом деле создать копию строки внутри ...

  • Указатель, возвращаемый c_str()data()) допустимо только до тех пор, пока не будут вызваны неконстантные методы в исходной строке.Это делает его использование неподходящим, когда функция C висит на указателе (в отличие от использования только во время фактического вызова функции).

  • Если есть любой вероятность того, что строка будет изменена, отбрасывание констант из c_str() не очень хорошая идея.Вы должны создать буфер с копией строки и передать его в функцию C.Если вы создаете буфер, не забудьте добавить нулевое завершение.

4 голосов
/ 12 апреля 2011

[Я хотел бы добавить комментарий, но мне не хватает представителя для этого, поэтому извините за добавление (еще) другого ответа.]

Хотя это правда, что текущий Стандарт не гарантирует непрерывность внутреннего буфера std :: string, похоже, что практически все реализации используют смежные буферы.Кроме того, новый стандарт C ++ 0x (который должен быть одобрен ISO) требует непрерывных внутренних буферов в std :: string, и даже текущий стандарт C ++ 03 требует возврата непрерывного буфера при вызове data () или& str [0] (хотя он не обязательно должен заканчиваться нулем).См. здесь для получения более подробной информации.

Это все еще не делает безопасным запись в строку, хотя стандарт не принуждает реализации к фактически возвращать их внутренний буфер когда вы вызываете data (), c_str () или operator, и им также не запрещается использовать оптимизации, такие как копирование при записи, что может еще больше осложнить ситуацию (похоже, что новый C ++ 0x запретит копирование-на пиши хоть).При этом, если вас не волнует максимальная переносимость, вы можете проверить свою целевую реализацию и посмотреть, что она на самом деле делает внутри.AFAIK, Visual C ++ 2008/2010 всегда возвращает реальный указатель внутреннего буфера и не выполняет копирование при записи (в нем есть функция оптимизации небольших строк, но это, вероятно, не является проблемой).

2 голосов
/ 12 апреля 2011

Когда функция C не изменяет строку за char*, вы можете использовать std::string::c_str() как для const, так и для неконстантных std::string экземпляров.В идеале это будет const char*, но если это не так (из-за устаревшего API), вы можете по закону использовать const_cast.Но вы можете использовать указатель из c_str(), только если не изменяете строку!

Когда функция C изменяет строку за char*, ваш единственный безопасный и портативный способ использованияstd::string - скопировать его во временный буфер самостоятельно (например, из c_str())!После этого убедитесь, что вы освободили временную память - или используйте std::vector, который гарантированно имеет непрерывную память.

1 голос
/ 12 апреля 2011
  1. std: строка может хранить ноль байтов. Это означает, что при передаче функции C она может быть преждевременно обрезана, так как функции C остановятся на первом нулевом байте. Это может иметь последствия для безопасности, если вы попытаетесь использовать функцию C, например, для фильтрации или экранирования нежелательных символов.

  2. Результат std :: string :: c_str () иногда будет недействительным из-за операций, изменяющих строку (неконстантные функции-члены). Будет очень сложно диагностировать ошибки («Heisenbugs»), если вы попытаетесь использовать этот указатель после того, как вы сначала используете c_str (), а затем измените строку.

  3. Не используйте const_cast, никогда. goto менее хлопотно.

...