如何使用iconv(3)将宽字符串转换为UTF-8?

Ano*_*eek 5 c linux unicode utf-8 iconv

我正在尝试使用iconv(3)将宽字符串转换为UTF-8,使用下面的代码.当我运行下面的命令时,iconv调用返回E2BIG,就好像输出缓冲区中没有足够的可用空间字节一样.尽管事实上(我认为)我确定了输出缓冲区的大小以承认UTF-8的最坏情况扩展,但仍会发生这种情况.实际上,假设输入是一个简单的ASCII"A"编码为wchar_t后跟一个零wchar_t终结符,输出应该是两个字节/字符:一个'A'后跟一个'\ 0'.

我的Linux系统上的'man utf-8'表示UTF-8字节序列的最大长度是6个字节,所以我相信对于2个wchar_ts的输入缓冲区(一个字符后跟空终止符),make(on我的系统)总共8个字节(因为sizeof(wchar_t)== 4),12个字节的缓冲区(2*UTF8_SEQUENCE_MAXLEN)就足够了.

通过实验,如果我将UTF8_SEQUENCE_MAXLEN增加到16,则iconv的返回值表示成功(15仍然失败).但是当我用UTF-8编码时,我无法看到任何wchar_t值会占用如此多的字节.

我的计算出错了吗?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;
}
Run Code Online (Sandbox Code Playgroud)

Ano*_*eek 9

iconv_open的参数是错误的.参数的顺序是(to,from),而不是(from,to),如联机帮助页中明确说明的那样.

因此,改变

iconv_open("WCHAR_T", "UTF-8");
Run Code Online (Sandbox Code Playgroud)

iconv_open("UTF-8", "WCHAR_T");
Run Code Online (Sandbox Code Playgroud)

导致上面的代码(否则未更改)按预期工作.

D'哦.需要更仔细地阅读联机帮助页.