5

以下のコードを使用して、iconv(3) を使用してワイド文字列を UTF-8 に変換しようとしています。以下を実行すると、iconv 呼び出しは E2BIG を返します。これは、出力バッファーに使用可能なスペースが十分にないかのようです。これは、(私が思うに) UTF-8 の最悪の場合の展開を許容するように出力バッファーのサイズを設定したという事実にもかかわらず発生します。実際、入力が wchar_t としてエンコードされた単純な ASCII 'A' であり、その後に 0 の wchar_t ターミネータが続く場合、出力は正確に 2 バイト/文字 ('A' の後に '\0' が続く) になるはずです。

Linux システムの 'man utf-8' は、UTF-8 バイト シーケンスの最大長が 6 バイトであることを示しています。私のシステム) 合計 8 バイト (sizeof(wchar_t) == 4 であるため)、12 バイト (2 * UTF8_SEQUENCE_MAXLEN) のバッファーで十分なはずです。

実験では、UTF8_SEQUENCE_MAXLEN を 16 に増やした場合、iconv の戻り値は成功を示します (15 はまだ失敗します)。しかし、UTF-8 でエンコードされた場合、wchar_t 値が非常に多くのバイトを占有する方法はわかりません。

私の計算は間違っていませんか?16 バイトの UTF-8 シーケンスは可能ですか? 私は何を間違えましたか?

#include <stdio.h>
#include <stdlib.h>
#include <iconv.h>
#include <wchar.h>

#define UTF8_SEQUENCE_MAXLEN 6
/* #define UTF8_SEQUENCE_MAXLEN 16 */

int
main(int argc, char **argv)
{
    wchar_t *wcs = L"A";
    signed char utf8[(1 /* wcslen(wcs) */ + 1 /* L'\0' */) * UTF8_SEQUENCE_MAXLEN];
    char *iconv_in = (char *) wcs;
    char *iconv_out = (char *) &utf8[0];
    size_t iconv_in_bytes = (wcslen(wcs) + 1 /* L'\0' */) * sizeof(wchar_t);
    size_t iconv_out_bytes = sizeof(utf8);
    size_t ret;
    iconv_t cd;

    cd = iconv_open("WCHAR_T", "UTF-8");
    if ((iconv_t) -1 == cd) {
        perror("iconv_open");
        return EXIT_FAILURE;
    }

    ret = iconv(cd, &iconv_in, &iconv_in_bytes, &iconv_out, &iconv_out_bytes);
    if ((size_t) -1 == ret) {
        perror("iconv");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
4

1 に答える 1

10

iconv_open の引数が間違っています。マンページに明確に記載されているように、引数の順序は (to, from) であり、(from, to) ではありません。

その結果、変更

iconv_open("WCHAR_T", "UTF-8");

iconv_open("UTF-8", "WCHAR_T");

上記の (それ以外は変更されていない) コードが期待どおりに動作します。

ああ。マンページをもっとよく読む必要があります。

于 2013-11-03T10:36:39.977 に答える