質問

私は、ASCII文字列とユニコード文字列の間で簡単に変換できるようにする簡単なデータストラクチャを作成しようとしています。私の問題は、関数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
    }
}
役に立ちましたか?

解決

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

さらに、使用する代わりに strlen(str) 変換された文字列の長さを決定するには、使用する必要があります mbstowcs(0, src, 0) + 1. 。また、タイプを変更する必要があります strconst 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
    }
}

マーク・ベニングフィールドはそれを指摘します mbstowcs(0, src, 0) C標準のPOSIX / XSI拡張です - 標準Cのみで必要な長さを取得するには、代わりに使用する必要があります。

    const char *src_copy = src;
    obj->length = mbstowcs(NULL, &src_copy, 0, NULL);

他のヒント

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

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

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

編集: 議論すると、不適合なWindowsバージョンを使用しているように見えます。 mbstowcs 働き。もしそうなら、あなたの質問はそのように反映するために更新されるべきです。

編集2: コードはたまたま私のために働いただけです malloc 新鮮なゼロ充填バッファーを返しました。あなたが通り過ぎているので obj->lengthmbstowcs の最大数として wchar_t 宛先に書き込む値は、スペースがなくなり、ソース文字列に適切なマルチバイト文字(単一のバイトを超える必要があるもの)がない限り、Nullターミネーターを書き込むことができません。これを変更します obj->length+1 そして、それは正常に動作するはずです。

UTF-8をロケールとしてUbuntu Linuxで実行しています。

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

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

長さ= 6

!C Stringこんにちは! wchar string hello!xxxxxxxxxxxxxxxxxxxxxxxxに変換

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

長さの故障!

参照printf( "wcslen =%d n"、(int)wcslen(obj-> string)); wcslen = 11として印刷します

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top