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