charをwchar_tに変換する問題(長さが間違っています)
質問
私は、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
. 。また、タイプを変更する必要があります str
に 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
}
}
マーク・ベニングフィールドはそれを指摘します 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->length
に mbstowcs
の最大数として 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として印刷します