Я пытаюсь использовать iconv(3) для преобразования строки широких символов в UTF-8, используя приведенный ниже код. Когда я запускаю приведенное ниже, вызов iconv возвращает E2BIG, как будто в выходном буфере недостаточно байтов свободного места. Это происходит, несмотря на то, что (я думаю) размер выходного буфера таков, чтобы допустить наихудшее расширение для UTF-8. На самом деле, учитывая, что ввод представляет собой простую ASCII-символ, закодированную как wchar_t, за которой следует нулевой терминатор wchar_t, вывод должен состоять ровно из двух байтов/символов: «A», за которым следует «\0».
'man utf-8' в моей системе Linux говорит, что максимальная длина последовательности байтов UTF-8 составляет 6 байтов, поэтому я считаю, что для входного буфера из 2 wchar_ts (символ, за которым следует завершающий нуль), что делает (на моя система) всего 8 байт (поскольку sizeof(wchar_t) == 4), буфера в 12 байт (2 * UTF8_SEQUENCE_MAXLEN) должно быть достаточно.
Экспериментально, если я увеличу UTF8_SEQUENCE_MAXLEN до 16, возвращаемое значение iconv указывает на успех (15 по-прежнему не работает). Но я не вижу никакого способа, чтобы любое значение wchar_t занимало столько байтов при кодировании в UTF-8.
Я ошибся в своих расчетах? Возможны ли 16-байтовые последовательности UTF-8? Что я сделал не так?
#include <stdio.h>
#include <stdlib.h>
#include <iconv.h>
#include <wchar.h>
#define UTF8_SEQUENCE_MAXLEN 6
/* #define UTF8_SEQUENCE_MAXLEN 16 */
int
main(int argc, char **argv)
{
wchar_t *wcs = L"A";
signed char utf8[(1 /* wcslen(wcs) */ + 1 /* L'\0' */) * UTF8_SEQUENCE_MAXLEN];
char *iconv_in = (char *) wcs;
char *iconv_out = (char *) &utf8[0];
size_t iconv_in_bytes = (wcslen(wcs) + 1 /* L'\0' */) * sizeof(wchar_t);
size_t iconv_out_bytes = sizeof(utf8);
size_t ret;
iconv_t cd;
cd = iconv_open("WCHAR_T", "UTF-8");
if ((iconv_t) -1 == cd) {
perror("iconv_open");
return EXIT_FAILURE;
}
ret = iconv(cd, &iconv_in, &iconv_in_bytes, &iconv_out, &iconv_out_bytes);
if ((size_t) -1 == ret) {
perror("iconv");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}