1

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

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

'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 中使用,所以我认为虽然它可能更丑陋,但我将在那里执行字符串转换。它只是工作。

4

1 回答 1

2

您没有显示变量stringLen和的声明或初始化outbytes,您的问题很可能就在那里。然而,这...

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

……非常麻烦。该iconv()函数期望它的第三个和第五个参数是 type 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(即 NULL 指针),那么这将构成iconv().

于 2014-11-17T20:16:03.643 回答