在C中将UTF-16LE转换为UTF-8

时间:2014-11-17 19:56:36

标签: c encoding utf-8 character-encoding utf-16le

我使用的库有一个函数,它返回在标准char *中编码为UTF-16LE(我很确定)的结果字符串,以及字符串中的字节数。我想将这些字符串转换为UTF-8。我尝试了这个问题的解决方案:Convert UTF-16 to UTF-8 under Windows and Linux, in 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);
}

然后我调用库函数来填充数据的拒绝。查看调试器中的缓冲区,我可以看到缓冲区中的数据。例如,如果数据是“test”,我会看到以下内容查看拒绝的各个索引:

'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);

结果是outbuff和resbuff都以空字符串结束。

请注意,我将stringlen声明为int而不是unsigned long,因为这是库函数所期望的。

编辑:我根据John Bollinger在下面的回答略微调整了我的代码,但它没有改变结果。

编辑2:最终这段代码的输出将在Python中使用,所以我想虽然它可能更丑,但我只是在那里执行字符串转换。它只是有效。

1 个答案:

答案 0 :(得分:2)

您没有显示变量stringLenoutbytes的声明或初始化,您的问题可能就在那里。但是,这......

  

请注意,我将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至少不是C字符串。嵌入在数据中的空字符使字符串解释不合适。但是,根据输入和输出缓冲区的初始化方式,可能是在iconv()完成后,*resbuff == '\0'*outbuff == '\0'(指您自己的当前代码)。顺便说一句,我称之为“空”字符串,而不是“空”字符串。如果您的确意味着iconv()离开resbuff == 0outbuff == 0(即空指针),那么这将构成iconv()中的错误。