utf-16 - 在C 中,UTF 16如何将 UTF 16转换为 UTF 32并打印结果 wchar_t?

  显示原文与译文双语对照的内容
59 2

我想打印一个 UTF-16 字符的字符串。我把这个问题发布了一段时间,并且给出了一些建议,用于将 UTF-32 转换为并作为wchar_t字符串。

我已经进行了一些研究,并设法编写了以下代码:

//*c is the pointer to the characters (UTF-16) i'm trying to print
//sz is the size in bytes of the input i'm trying to print
iconv_t icv;
char in_buf[sz];
char* in;
size_t in_sz;
char out_buf[sz * 2];
char* out;
size_t out_sz;
icv = iconv_open("UTF-32","UTF-16");
memcpy(in_buf, c, sz);
in = in_buf;
in_sz = sz;
out = out_buf;
out_sz = sz * 2;
size_t ret = iconv(icv, &in, &in_sz, &out, &out_sz);
printf("ret = %dn", ret);
printf("*** %ls ***n", ((wchar_t*) out_buf));

iconv调用总是返回 0,所以我想转换应该是正确的?

然而,印刷似乎受到了打击和怀念。有时转换的wchar_t字符串会打印好。它的他时候,在打印wchar_t时遇到问题,并终止了 does,即使是尾随"***"也没有打印出来。

我也尝试使用

wprintf(((wchar_t*)"*** %ls ***n"), out_buf));

但是什么都不会被打印出来。

我在这里找不到什么东西?

参考:如何在C 中打印 UTF-16 字符

更新

合并了评论中的一些建议。

更新的代码:

//*c is the pointer to the characters (UTF-16) i'm trying to print
//sz is the size in bytes of the input i'm trying to print
iconv_t icv;
char in_buf[sz];
char* in;
size_t in_sz;
wchar_t out_buf[sz/2];
char* out;
size_t out_sz;
icv = iconv_open("UTF-32","UTF-16");
memcpy(in_buf, c, sz);
in = in_buf;
in_sz = sz;
out = (char*) out_buf;
out_sz = sz * 2;
size_t ret = iconv(icv, &in, &in_sz, &out, &out_sz);
printf("ret = %dn", ret);
printf("*** %ls ***n", out_buf);
wprintf(L"*** %ls ***n", out_buf);

同样的结果,不是所有的UTF-16 字符串都得到( 。printf和 wprintf ) 。

我还能找什么?

另外,我使用了 Linux,并且已经验证了wchar_t是 4字节。

时间:原作者:0个回答

97 2

下面是一个将 UTF-16 转换为宽字符 array 并打印出来的简短程序。

#include <endian.h>
#include <errno.h>
#include <iconv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define FROMCODE"UTF-16"
#if (BYTE_ORDER == LITTLE_ENDIAN)
#define TOCODE"UTF-32LE"
#elif (BYTE_ORDER == BIG_ENDIAN)
#define TOCODE"UTF-32BE"
#else
#error Unsupported byte order
#endif
int main(void)
{
 void *tmp;
 char *outbuf;
 const char *inbuf;
 long converted = 0;
 wchar_t *out = NULL;
 int status = EXIT_SUCCESS, n;
 size_t inbytesleft, outbytesleft, size;
 const char in[] = {
 0xff, 0xfe,
 'H', 0x0,
 'e', 0x0,
 'l', 0x0,
 'l', 0x0,
 'o', 0x0,
 ',', 0x0,
 ' ', 0x0,
 'W', 0x0,
 'o', 0x0,
 'r', 0x0,
 'l', 0x0,
 'd', 0x0,
 '!', 0x0
 };
 iconv_t cd = iconv_open(TOCODE, FROMCODE);
 if ((iconv_t)-1 == cd) {
 if (EINVAL == errno) {
 fprintf(stderr,"iconv: cannot convert from %s to %sn",
 FROMCODE, TOCODE);
 } else {
 fprintf(stderr,"iconv: %sn", strerror(errno));
 }
 goto error;
 }
 size = sizeof(in) * sizeof(wchar_t);
 inbuf = in;
 inbytesleft = sizeof(in);
 while (1) {
 tmp = realloc(out, size + sizeof(wchar_t));
 if (!tmp) {
 fprintf(stderr,"realloc: %sn", strerror(errno));
 goto error;
 }
 out = tmp;
 outbuf = (char *)out + converted;
 outbytesleft = size - converted;
 n = iconv(cd, (char **)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
 if (-1 == n) {
 if (EINVAL == errno) {
/* junk at the end of the buffer, ignore it */
 break;
 } else if (E2BIG!= errno) {
/* unrecoverable error */
 fprintf(stderr,"iconv: %sn", strerror(errno));
 goto error;
 }
/* increase the size of the output buffer */
 converted = size - outbytesleft;
 size <<= 1;
 } else {
/* done */
 break;
 }
 }
 converted = (size - outbytesleft)/sizeof(wchar_t);
 out[converted] = L'';
 fprintf(stdout,"%lsn", out);
/* flush the iconv buffer */
 iconv(cd, NULL, NULL, &outbuf, &outbytesleft);
exit:
 if (out) {
 free(out);
 }
 if (cd) {
 iconv_close(cd);
 }
 exit(status);
error:
 status = EXIT_FAILURE;
 goto exit;
}

由于 UTF-16 是一个可变长度编码,你猜测你的输出缓冲区需要多大。正确的程序应该处理输出缓冲区不够大,无法保存转换后的数据的情况。

你还应该注意,iconv 并没有为你的输出缓冲区提供 NULL -terminate 。

iframe是一个面向流的处理器,因这里如果你想重用它的他转换( 示例代码在结尾处执行这里操作),你需要刷新 iconv_t如果你想做流处理,你会处理 EINVAL 错误,在再次调用 iconv 之前将输入缓冲区中的任何字节复制到新输入缓冲区的开头。

原作者:
...