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

标签 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);
}

然后我调用库函数用数据填充 rebuff。查看调试器中的缓冲区,我可以看到缓冲区中的数据。例如,如果数据是“test”,我会看到以下查看 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 中使用,所以我认为虽然它可能更丑陋,但我将在那里执行字符串转换。它只是工作。

最佳答案

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

Note that I declare stringlen as an int rather than an unsigned long because that is what the library function is expecting.

……很麻烦。 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 and resbuff both end up as null strings.

这根本不是一回事。

iconv() 函数更新 指向输入和输出缓冲区的指针,以便于通过多次调用转换长输入,这种需求相当普遍。这就是为什么您必须将指针传递给这些指针的原因。如果您不想丢失这些指针的原始值,那么您应该制作并传递副本;我已经更新了上面的代码来证明这一点。

此外,iconv() 返回错误指示符或不可逆转换字符的计数,而不是转换字符总数的计数。对于有效的 UTF-16{,LE,BE} 到 UTF-8,不应该有任何不可逆的转换。返回值为零表示指定数量的输入字节已全部成功且可逆地转换为输出字节。

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

关于在 C 中将 UTF-16LE 转换为 UTF-8,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26980851/

相关文章:

json - 解码或转义\u00f0\u009f\u0091\u008d 到 👍

c - Gdk-Pixbuf (Gtk-Image?) 默认支持哪些图像格式?

java - 检测并更改编码

xslt - 防止 XSLT 输出中出现窄不间断空格 (n-nbsp)

ios - “???”显示在 iOS 设备上的字符串中,但不是模拟器

java - UTF-8 和 UTF-16 的区别?

c - 将数组中的十六进制转换为ascii,以便在C语言中进行比较

c - 将 Photoshop 不透明蒙版模拟为 HLSL ShaderEffect

c - extern Short i 有什么问题;我=2; ? gcc 提示类型冲突

svn - svn 的 svnlook 结果中的西里尔字母支持