Кодировка символов C++ при преобразовании из строки в const char* для интерфейса Ruby FFI

Я использую внешнюю библиотеку C++, которая осуществляет связь по протоколу HTTPS и предоставляет ответ XML-сервера. На стороне сервера ответ кодируется через ISO-8859-15, и я получаю std::string, представляющий этот ответ из API. Когда я распечатываю/записываю его в файл, он выглядит правильно.

Коды ошибок std::string и int должны быть переданы моему внешнему вызывающему абоненту. Поэтому я возвращаю оба значения внутри структуры:

extern "C" {
  struct FoobarResponse {
    const char* responseText;
    int returnCode;
  };
}

К сожалению, раньше мне приходилось преобразовывать ответ std::string в строковое представление const char* в стиле C с помощью std::c_str(). Причина: Мой вызывающий объект — это сценарий Ruby, использующий Ruby FFI для связи с моей библиотекой C++, а межъязыковое преобразование здесь — Ruby::string -> C::const char*.

Здесь интересно: если я std::cout преобразовал строку после того, как поместил ее в структуру, все еще в порядке.

Проблема: при обработке ответа сервера на стороне Ruby он не работает. Вместо исходного ответа, например:

<?xml version="1.0" encoding="ISO-8859-15"?>
<Foobar xmlns="http://www.foobar.com/2012/XMLSchema">
  ...
</Foobar>

Я получаю строку, явно содержащую непечатаемые символы, которая всегда прерывается в начале и в конце.

?O[
l version="1.0" encoding="ISO-8859-15"?>
<Foobar xmlns="http://www.foobar.com/2012/XMLSchema">
</Fo??

На самом деле строка содержит как минимум переводы строк, возвраты каретки и табуляции, а может и больше.

Я пробовал :force_encoding строку на стороне Ruby как ASCII-8BIT, ISO-8859-15 и UTF-8, без изменений. Я попытался кодировать base64 на стороне C++, прежде чем поместить строку в структуру и декодировать base64 на стороне Ruby, используя этот код, без изменений.

У меня было бесчисленное количество попыток преобразовать строку с помощью Iconv, без изменений.

Я также пытался удалить непечатаемые символы из строки, прежде чем помещать ее в структуру, но мне это не удалось.

Я понятия не имею, что здесь происходит, и у меня заканчиваются варианты. Может ли кто-нибудь указать мне правильное направление?

С уважением Феликс


person GeorgieF    schedule 30.07.2013    source источник


Ответы (1)


Значение, возвращаемое c_str(), уничтожается, как только std::string выходит за пределы области действия. Если вы собираетесь передать это значение в свой сценарий, вам следует выделить память и скопировать строку в новое выделенное пространство. См. этот пример: http://www.cplusplus.com/reference/string/string/c_str/

Вы также должны убедиться, что сценарий ruby ​​будет правильно освобождать память.

Я думаю, это то, что там объясняется: https://github.com/ffi/ffi/wiki/Examples .

Пример со структурой, переданной в Ruby из C: https://github.com/ffi/ffi/wiki/Examples#-structs

person fjardon    schedule 30.07.2013
comment
Я не передаю строки из C в Ruby. Я использую структуру, упомянутую выше. Структура создается моей библиотекой C, и память, используемая структурой, также впоследствии освобождается. На стороне Ruby я отражаю структуру и могу получить к ней доступ. Строки в структуре доступны. Только они неправильно сформированы. Если бы память была уничтожена слишком рано, у меня не было бы доступа к строке в Ruby, не так ли? - person GeorgieF; 30.07.2013
comment
Но ваша структура содержит член char*. Вы должны выделить память для этого char* и скопировать c_str() в это вновь выделенное пространство. Вы также должны освободить эту память ПЕРЕД освобождением памяти для вашей структуры. - person fjardon; 30.07.2013
comment
Вы бы получили доступ к памяти, но она была бы полна мусора. Это именно то, что вы видите. - person fjardon; 30.07.2013
comment
Почувствуй себя дураком. Я не выделял память под строки внутри структуры. Работает сейчас. Спасибо @fjardon, проголосовал. - person GeorgieF; 30.07.2013