2013-11-03 50 views
3

我想使用iconv(3)使用下面的代码将宽字符字符串转换为UTF-8。当我运行下面的代码时,iconv调用返回E2BIG,就好像输出缓冲区中没有足够的可用空间字节。尽管(我认为)我已经调整了输出缓冲区的大小以承认UTF-8的最坏情况扩展,但这种情况仍然发生。事实上,假设输入是一个简单的ASCII'A',编码为wchar_t,后面跟着一个零wchar_t终止符,输出应该恰好是两个字节/字符:一个'A'后跟一个'\ 0'。如何使用iconv(3)将宽字符串转换为UTF-8?

我的Linux系统上的'man utf-8'表示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; 
} 

回答

5

iconv_open的参数是错误的。 参数的顺序是(to,from),not(from,to),正如手册页中清楚说明的那样。

因此,更改

iconv_open("WCHAR_T", "UTF-8"); 

iconv_open("UTF-8", "WCHAR_T"); 

使(否则不变)码上方以预期方式工作。

D'oh。需要更仔细地阅读手册。