2

ASCII 文字列と Unicode 文字列を簡単に相互に変換できる単純なデータ構造を作成しようとしています。私の問題は、関数 mbstowcs によって返される長さは正しいが、新しく作成された wchar_t 文字列で関数 wcslen によって返される長さが正しくないことです。ここで何か不足していますか?

typedef struct{

    wchar_t *string;
    long length; // I have also tried int, and size_t
} String;

void setCString(String *obj, char *str){

    obj->length = strlen(str);

    free(obj->string); // Free original string
    obj->string = (wchar_t *)malloc((obj->length + 1) * sizeof(wchar_t)); //Allocate space for new string to be copied to

    //memset(obj->string,'\0',(obj->length + 1)); NOTE: I tried this but it doesn't make any difference

    size_t length = 0;

    length = mbstowcs(obj->string, (const char *)str, obj->length);

    printf("Length = %d\n",(int)length); // Prints correct length
    printf("!C string %s converted to wchar string %ls\n",str,obj->string); //obj->string is of a wcslen size larger than Length above...

    if(length != wcslen(obj->string))
            printf("Length failure!\n");

    if(length == -1)
    {
        //Conversion failed, set string to NULL terminated character
        free(obj->string);
        obj->string = (wchar_t *)malloc(sizeof(wchar_t));
        obj->string = L'\0';
    }
    else
    {
        //Conversion worked! but wcslen (and printf("%ls)) show the string is actually larger than length
        //do stuff
    }
}
4

3 に答える 3

2

コードは私にとってはうまくいくようです。渡す文字列の内容や、使用しているロケールなど、より多くのコンテキストを提供できますか?

私が気づいた他のいくつかのバグ/スタイルの問題:

  • obj->length(ワイド) 文字の長さに一致するように更新されるのではなく、割り当てられた長さのままになります。それはあなたの意図ですか?
  • へのキャストconst char *は役に立たず、悪いスタイルです。

編集:議論の結果、関数の非準拠の Windows バージョンを使用しているようですmbstowcs。その場合は、質問を更新してそのように反映する必要があります。

編集 2:mallocゼロで埋められた新鮮なバッファが返されたため、コードがたまたま機能しただけです。宛先に書き込む値の最大数としてを渡しobj->lengthているため、適切なマルチバイト文字 (1 バイト以上を必要とする文字) が含まれていない限り、スペースが不足し、null ターミネータを書き込むことができません。ソース文字列。これをに変更すると、正常に動作するはずです。mbstowcswchar_tobj->length+1

于 2010-10-06T02:11:33.557 に答える
1

に渡す必要がある長さにはターミネータ文字がmbstowcs() 含まれますが、 で計算された長さには含まれません - に渡される値に 1 を追加する必要があります。L'\0'obj->length()mbstowcs()

さらにstrlen(str)、変換された文字列の長さを決定するために を使用する代わりに、 を使用する必要がありますmbstowcs(0, src, 0) + 1strの型をに変更しconst char *、キャストを削除 する必要もあります。ペアrealloc()代わりに使えます。free() / malloc()全体として、次のようになります。

typedef struct {
    wchar_t *string;
    size_t length;
} String;

void setCString(String *obj, const char *str)
{
    obj->length = mbstowcs(0, src, 0);
    obj->string = realloc(obj->string, (obj->length + 1) * sizeof(wchar_t)); 

    size_t length = mbstowcs(obj->string, str, obj->length + 1);

    printf("Length = %zu\n", length);
    printf("!C string %s converted to wchar string %ls\n", str, obj->string);

    if (length != wcslen(obj->string))
            printf("Length failure!\n");

    if (length == (size_t)-1)
    {
        //Conversion failed, set string to NULL terminated character
        obj->string = realloc(obj->string, sizeof(wchar_t));
        obj->string = L'\0';
    }
    else
    {
        //Conversion worked!
        //do stuff
    }
}

Mark Benningfield は、これは C 標準の POSIX / XSI 拡張であると指摘していmbstowcs(0, src, 0)ます。標準 C のみで必要な長さを取得するには、代わりに次を使用する必要があります。

    const char *src_copy = src;
    obj->length = mbstowcs(NULL, &src_copy, 0, NULL);
于 2010-10-06T10:04:34.690 に答える
0

ロケールとしてUTF-8を使用してUbuntuLinuxでこれを実行しています。

要求された追加情報は次のとおりです。

完全に割り当てられた構造でこの関数を呼び出し、ハードコードされた「文字列」(L「文字列」ではない)を渡します。したがって、基本的にsetCString(* obj、 "Hello!")で関数を呼び出します。

長さ=6

!C文字列こんにちは!wchar文字列に変換Hello!xxxxxxxxxxxxxxxxxxxx

(ここで、x =ランダムデータ)

長さの失敗!

参照用printf( "wcslen =%d \ n"、(int)wcslen(obj-> string)); wcslen=11として出力されます

于 2010-10-06T02:30:41.613 に答える