1

標準の char * で UTF-16LE としてエンコードされた結果文字列 (私はかなり確信しています) と、文字列内のバイト数を返す関数を持つライブラリを使用しています。これらの文字列を UTF-8 に変換したいと思います。私はこの質問から解決策を試しました: Windows と Linux で UTF-16 を UTF-8 に変換します。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 にデータを入力します。デバッガーでバッファーを見ると、バッファー内のデータが表示されます。たとえば、データが「テスト」の場合、リバフの個々のインデックスを見ると、次のようになります。

'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 の両方が null 文字列になります。

ライブラリ関数が想定しているのは、stringlen を unsigned long ではなく int として宣言していることに注意してください。

編集: 以下の John Bollinger の回答に従って、コードを少し調整しましたが、結果は変わりませんでした。

編集 2: 最終的に、このコードからの出力は Python で使用されるため、見苦しいかもしれませんが、そこで文字列変換を実行するだけだと考えています。それだけで機能します。

4

1 に答える 1

2

stringLen変数およびの宣言または初期化を示していないため、outbytes問題がそこにある可能性があります。しかし、これは...

ライブラリ関数が想定しているのは、stringlen を unsigned long ではなく int として宣言していることに注意してください。

…とても困ります。このiconv()関数は、3 番目と 5 番目の引数が typesize_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 と resbuff はどちらもヌル文字列になります。

これはまったく同じではありません。

このiconv()関数は、入力バッファーと出力バッファーへのポインターを更新して、複数の呼び出しによる長い入力の変換を容易にします。これはかなり一般的です。そのため、これらのポインターにポインターを渡す必要があります。これらのポインタの元の値を失いたくない場合は、コピーを作成して渡す必要があります。これを示すために、上記のコードを更新しました。

さらに、iconv()変換された文字の総数ではなく、エラー インジケーターまたは不可逆的に変換された文字の数を返します。有効な UTF-16{,LE,BE} から UTF-8 への変換には、元に戻せない変換があってはなりません。ゼロの戻り値は、指定された数の入力バイトがすべて正常に出力バイトに可逆的に変換されたことを示します。

resbuffまた、少なくとも C 文字列ではなかったことに注意してください。データにヌル文字が埋め込まれていると、文字列の解釈が不適切になります。ただし、入力バッファーと出力バッファーがどのように初期化されたかによっては、iconv()終了後(独自の現在のコードを参照) になる可能性が*resbuff == '\0'あります。*outbuff == '\0'ちなみに、これらの「空」文字列は「null」文字列ではなく、「空」文字列と呼びます。iconv()resbuff == 0and (つまり NULL ポインター)を本当に意味する場合outbuff == 0、それは のバグになりiconv()ます。

于 2014-11-17T20:16:03.643 に答える