在C语言中使用iconv将Unicode代码点转换为UTF-8

3
我想将一个32位的值,它代表一个Unicode码点,转换成一串只包含对应字符的utf-8编码字符串的char序列。
例如,我想将值955转换成utf-8编码字符串"λ"
我尝试使用iconv来实现这个目标,但我没有得到期望的结果。以下是我编写的代码:
#include <stdio.h>
#include <iconv.h>
#include <stdint.h>

int main(void)
{
  uint32_t codepoint = U'λ';
  char *input = (char *) &codepoint;
  size_t in_size = 2; // lower-case lambda is a 16-bit character (0x3BB = 955)

  char output_buffer[10];
  char *output = output_buffer;
  size_t out_size = 10;

  iconv_t cd = iconv_open("UTF-8", "UTF-32");

  iconv(cd, &input, &in_size, &output, &out_size);

  puts(output_buffer);

  return 0;
}

当我运行它时,只有一个换行符被打印出来(puts 自动打印一个换行符,-- outout_buffer 的第一个字节是 '\0')。我的理解或实现有什么问题吗?

1
请注意,iconv_open 函数的参数顺序为目标编码,源编码。 - Ry-
我知道,我试图做其他事情,忘记改回来了。谢谢你发现了这个问题。不幸的是,它仍然无法正常工作。 - Bradley Garagan
2个回答

3
正如minitech所说,对于UTF32,您必须在uint32_t中使用size = 4,并且您必须将缓冲区预设为null以在转换后具有终止null。
这段代码在Ubuntu上可以正常工作:
#include <stdio.h>
#include <iconv.h>
#include <stdint.h>
#include <memory.h>

int main(void)
{
  uint32_t codepoint = 955;
  char *input = (char *) &codepoint;
  size_t in_size = 4; // lower-case lambda is a 16-bit character (0x3BB = 955)

  char output_buffer[10];
  memset(output_buffer, 0, sizeof(output_buffer));
  char *output = output_buffer;
  size_t out_size = 10;

  iconv_t cd = iconv_open("UTF-8", "UTF-32");

  iconv(cd, &input, &in_size, &output, &out_size);

  puts(output_buffer);

  return 0;
}

2

两个问题:

  1. Since you’re using UTF-32, you need to specify 4 bytes. The “lower-case lambda is a 16-bit character (0x3BB = 955)” comment isn’t true for a 4-byte fixed-width encoding; it’s 0x000003bb. Set size_t in_size = 4;.

  2. iconv doesn’t add null terminators for you; it adjusts the pointers it’s given. You’ll want to add your own before calling puts.

    *output = '\0';
    puts(output_buffer);
    

调用 iconv 的时候将 errno 设置为 EISEQ,根据 iconv 的 man 手册,这意味着输入序列无效。我已经合并了你提出的两个更改建议。 - Bradley Garagan
@BradleyGaragan:char codepoint[4]; codepoint[0] = 0xbb; codepoint[1] = 0x03; codepoint[2] = 0x00; codepoint[3] = 0x00; char *input = codepoint; 这段代码能正常工作吗? - Ry-
@BradleyGaragan:如果你把 03 交换,12 交换呢? - Ry-
可以了!我猜这可能与字节序有关?不过我很好奇为什么 iconv 没有考虑到这一点。 - Bradley Garagan
@BradleyGaragan:是的,看起来是这样!我本以为字节序问题会出现在另一侧。无论如何,为了保持一致性,您可以指定UTF-32LE(或UTF-32BE)。 - Ry-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接