Конвертировать UTF-16LE в UTF-8 в C
Я использую библиотеку, в которой есть функция, которая возвращает строки результата, закодированные как UTF-16LE (я уверен) в стандартном char *, а также количество байтов в строке. Я хотел бы преобразовать эти строки в UTF-8. Я попробовал решение из этого вопроса: конвертировать UTF-16 в UTF-8 под Windows и Linux, в C, который говорит использовать iconv, однако в результате оба буфера ввода и вывода оказались пустыми. Что мне не хватает?
Мои входные и выходные буферы объявлены и инициализированы следующим образом:
char *resbuff=NULL;
char *outbuff=NULL;
int stringLen;
size_t outbytes=1024;
size_t inbytes;
size_t convResult;
...
//some loop and control code here
...
if (resbuff==NULL) {
resbuff=(char *)malloc(1024);
outbuff=(char *)malloc(1024);
}
Затем я вызываю библиотечную функцию, чтобы заполнить отпор данными. Глядя на буфер в отладчике, я вижу данные в буфере. Например, если данные "тестовые", я вижу следующее, глядя на отдельные индексы отпора:
't','\0','e','\0','s','\0','t','\0'
Я полагаю, что это UTF-16LE (другой код, использующий ту же библиотеку, чтобы подтвердить это), и stringlen теперь равен 8. Затем я пытаюсь преобразовать его в UTF-8, используя следующий код:
iconv_t conv;
conv=iconv_open("UTF-8", "UTF-16LE");
inbytes=stringLen;
convResult=iconv(conv,&resbuff,&inbytes,&outbuff,&outbytes); //this does return 0
iconv_close(conv);
В результате как исходящий, так и исходящий оба заканчиваются как нулевые строки.
Обратите внимание, что я объявляю stringlen как int, а не как unsigned long, потому что именно этого ожидает библиотечная функция.
РЕДАКТИРОВАТЬ: я немного подправил свой код в соответствии с ответом Джона Боллинджера ниже, но это не изменило результат.
РЕДАКТИРОВАТЬ 2: В конечном итоге вывод из этого кода будет использоваться в Python, поэтому я думаю, что, хотя это может быть и уродливее, я просто выполню там преобразование строк. Это просто работает.
1 ответ
Вы не показываете объявление или инициализацию переменных stringLen
а также outbytes
и ваша проблема вполне может лежать там. Тем не менее, это...
Обратите внимание, что я объявляю stringlen как int, а не как unsigned long, потому что именно этого ожидает библиотечная функция.
... очень беспокоит. iconv()
функция ожидает, что ее третий и пятый аргументы будут иметь тип size_t *
и ложь компилятору через приведение не заставит код фактически работать, если они на самом деле разные типы. Вы должны иметь что-то вроде этого:
size_t in_bytes_left = (expression giving the total input length, in bytes);
size_t out_bytes_available = (expression giving the size of the output buffer);
char *input_temp = resbuff;
char *output_temp = outbuff;
int result;
result = iconv(conv, &input_temp, &in_bytes_left, &output_temp, &out_bytes_available);
Также обратите внимание, что вы должны проверить возвращаемое значение, чтобы убедиться, что преобразование было завершено и успешно (в этом случае возвращаемое значение будет>= 0). Если оно меньше нуля, то значение errno
Сразу после звонка вам скажут, что за проблема возникла.
Отредактировано, чтобы добавить:
Вы изначально сказали, что нулевые байты были преобразованы, но теперь вы говорите, что
outbuff и resbuff оба заканчиваются как нулевые строки.
что совсем не одно и то же.
iconv()
Функция обновляет указатели на входной и выходной буферы, чтобы облегчить преобразование длинных входных данных с помощью нескольких вызовов, необходимость в этом довольно распространена. Вот почему вы должны передавать указатели на эти указатели. Если вы не хотите потерять первоначальные значения этих указателей, вам следует сделать и передать копии; Я обновил мой код выше, чтобы продемонстрировать это.
Дополнительно, iconv()
возвращает либо индикатор ошибки, либо количество необратимо преобразованных символов, а не общее количество преобразованных символов. Для действительных UTF-16{,LE,BE} в UTF-8 никогда не должно быть никаких необратимых преобразований. Возвращаемое значение ноль указывает, что указанное количество входных байтов было все успешно и обратимо преобразовано в выходные байты.
Обратите внимание, что resbuff
по крайней мере, никогда не был строкой Си. Нулевые символы, внедренные в данные, делают интерпретацию строки неуместной. Однако, в зависимости от того, как были инициализированы ваши входные и выходные буферы, после iconv()
отделки, *resbuff == '\0'
а также *outbuff == '\0'
(ссылаясь на ваш собственный текущий код). Кстати, я бы назвал эти "пустые" строки не "нулевыми". Если вы действительно имеете в виду, что iconv()
листья resbuff == 0
а также outbuff == 0
(т.е. указатели NULL), то это будет ошибка в iconv()
,