Подтвердить что ты не робот

Что следует учитывать при преобразовании функции std::string в функцию char * для C?

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

В принципе, важны три момента:

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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