【问题标题】:iconv encoding conversion problemiconv编码转换问题
【发布时间】:2010-01-29 14:05:24
【问题描述】:

我在将字符串从 utf8 转换为 gb2312 时遇到问题。我的转换功能在下面

void convert(const char *from_charset,const char *to_charset, char *inptr, char *outptr)
{
    size_t inleft = strlen(inptr);
    size_t outleft = inleft;
    iconv_t cd;     /* conversion descriptor */

    if ((cd = iconv_open(to_charset, from_charset)) == (iconv_t)(-1)) 
    {
            fprintf(stderr, "Cannot open converter from %s to %s\n", from_charset, to_charset);
            exit(8);
    }

    /* return code of iconv() */
    int rc = iconv(cd, &inptr, &inleft, &outptr, &outleft);
    if (rc == -1) 
    {
            fprintf(stderr, "Error in converting characters\n");

            if(errno == E2BIG)
                    printf("errno == E2BIG\n");
            if(errno == EILSEQ)
                    printf("errno == EILSEQ\n");
            if(errno == EINVAL)
                    printf("errno == EINVAL\n");

            iconv_close(cd);
            exit(8);
    }
    iconv_close(cd);
}

这是我如何使用它的示例:

int len = 1000;
char *result = new char[len];
convert("UTF-8", "GB2312", some_string, result);

编辑:我大多数时候都会遇到 E2BIG 错误。

【问题讨论】:

  • 如果您能告诉我们有关问题的想法会有所帮助。编译失败了吗?关联?在运行时?您看到的错误/输出是什么?
  • 你应该输入 inptr char const*,以避免混淆和可能的错误,因为它是不可修改的。

标签: c++ c iconv


【解决方案1】:

outleft 应该是输出缓冲区的大小(例如 1000 字节),而不是传入字符串的大小。

在转换时,字符串长度通常会在过程中发生变化,直到转换后您才能知道它会持续多长时间。 E2BIG 表示输出缓冲区不够大,在这种情况下,您需要给它更多的输出缓冲区空间(注意它已经转换了一些数据并相应地调整了传递给它的四个变量)。

【讨论】:

    【解决方案2】:

    正如其他人所指出的,E2BIG 意味着输出缓冲区不够大,无法进行转换,并且您为 outleft 使用了错误的值。

    但我也注意到您的功能可能存在其他一些问题。也就是说,根据您的函数的工作方式,您的调用者无法知道输出字符串中有多少字节。您的 convert() 函数既不会终止输出缓冲区,也没有办法告诉调用者它写入 outptr 的字节数。

    如果您想处理以 nul 结尾的字符串(看起来这就是您想要做的,因为您的输入字符串是以 nul 结尾的),您可能会发现以下方法要好得多:

    
    char *
    convert (const char *from_charset, const char *to_charset, const char *input)
    {
     size_t inleft, outleft, converted = 0;
     char *output, *outbuf, *tmp;
     const char *inbuf;
     size_t outlen;
     iconv_t cd;
    
     if ((cd = iconv_open (to_charset, from_charset)) == (iconv_t) -1)
      return NULL;
    
     inleft = strlen (input);
     inbuf = input;
    
     /* we'll start off allocating an output buffer which is the same size
      * as our input buffer. */
     outlen = inleft;
    
     /* we allocate 4 bytes more than what we need for nul-termination... */
     if (!(output = malloc (outlen + 4))) {
      iconv_close (cd);
      return NULL;
     }
    
     do {
      errno = 0;
      outbuf = output + converted;
      outleft = outlen - converted;
    
      converted = iconv (cd, (char **) &inbuf, &inleft, &outbuf, &outleft);
      if (converted != (size_t) -1 || errno == EINVAL) {
       /*
        * EINVAL  An  incomplete  multibyte sequence has been encoun­-
        *         tered in the input.
        *
        * We'll just truncate it and ignore it.
        */
       break;
      }
    
      if (errno != E2BIG) {
       /*
        * EILSEQ An invalid multibyte sequence has been  encountered
        *        in the input.
        *
        * Bad input, we can't really recover from this. 
        */
       iconv_close (cd);
       free (output);
       return NULL;
      }
    
      /*
       * E2BIG   There is not sufficient room at *outbuf.
       *
       * We just need to grow our outbuffer and try again.
       */
    
      converted = outbuf - out;
      outlen += inleft * 2 + 8;
    
      if (!(tmp = realloc (output, outlen + 4))) {
       iconv_close (cd);
       free (output);
       return NULL;
      }
    
      output = tmp;
      outbuf = output + converted;
     } while (1);
    
     /* flush the iconv conversion */
     iconv (cd, NULL, NULL, &outbuf, &outleft);
     iconv_close (cd);
    
     /* Note: not all charsets can be nul-terminated with a single
      * nul byte. UCS2, for example, needs 2 nul bytes and UCS4
      * needs 4. I hope that 4 nul bytes is enough to terminate all
      * multibyte charsets? */
    
     /* nul-terminate the string */
     memset (outbuf, 0, 4);
    
     return output;
    }
    

    【讨论】:

    • 你有一个小错误:converted = outbuf - out; 应该是converted = outbuf - output;。此外,我认为EILSEQ 的“中止一切”解决方案是矫枉过正;请参阅stackoverflow.com/questions/9249628/… 了解这是一个问题的情况。
    • 您唯一能做的就是开始丢弃字节,直到转换完成。这很少是一个好的解决方案。最好返回失败并提示用户。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    相关资源
    最近更新 更多