2012-04-04 11 views
5

シングルバイト文字列にダブルバイト文字列をフォーマットするのprintfを使用して:なぜprintfはユニコードパラメータをフォーマットしないのですか?

printf("%ls\n", L"s:\\яшертыHello"); // %ls for a wide string (%s varies meaning depending on the project's unicode settings). 

は明らかに、いくつかの文字は、ASCII文字として表現することができないので、時々私はダブルバイト文字の行動を見てきました「?」に変わるマーク文字。しかし、これは特定の文字に依存するようです。上記のprintfの場合、出力は次のようになります。

s:\ 

私は私のようなものかもしれません期待していた:私は例を失ってしまった怖いが、私は1つの文字列ときのためだと思う

s:\??????Hello 

をそれはユニコード文字を遭遇し、最初のものを '?'残りをあきらめた。

私の質問は、ワイド文字列をシングルバイト文字列にフォーマットするときに起こりそうなことです。ここに書類:http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspxは「文字は最初のヌル文字まで表示されます」と述べています。しかし、私はそれを見ていない。これはprintfのバグですか、どこかに書かれているような動作です。

ありがとうございました。私のprintfを使用する選択肢を与える人から回答を

UPDATE

感謝。私は別の方法に変更しようとしていますが、私は本当に好奇心から興味を持っています。なぜprintfは信頼できる文書化された動作をしていません。まるでそれを実装した人がこれを働かせないようにしてしまったように見えます。

+2

「%ls」ではなく書式指定子として「%S」を試しましたか? –

+0

はい。あなたのプロジェクトにUNICODEが定義されていない場合、%Sと%lsは同じ意味を持っていると思います。 –

+1

フォーマットの仕様を読んでいます(私は同意しません)。プロジェクト設定にUNICODEが定義されていない場合はSがワイド文字列用に、UNICODEが定義されている場合はSはシングルバイト文字列用です。 %lsは、UNICODE用に構築しているかどうかにかかわらず、ワイド文字列用です。 %sも意味が異なりますが、%hsは常にシングルバイト文字列です。 –

答えて

10

あなたのコードは動作すると期待しています。これはLinux上で動作しますが、ロケールに依存します。つまり、ロケールを設定しなければならず、ロケールは使用されている文字セットをサポートしなければなりません。ここに私のテストプログラムは次のとおりです。

#include <locale.h> 
#include <stdio.h> 

int main() 
{ 
    int c; 
    char* l = setlocale(LC_ALL, ""); 
    if (l == NULL) { 
     printf("Locale not set\n"); 
    } else { 
     printf("Locale set to %s\n", l); 
    } 
    printf("%ls\n", L"s:\\яшертыHello"); 
    return 0; 
} 

、ここでは、実行トレースです:

$ env LC_ALL=en_US.utf8 ./a.out 
Locale set to en_US.utf8 
s:\яшертыHello 

それはロケールが設定されていないか、または「C」に設定されていることを述べていた場合、それはあなたの正常な動作です期待した結果を得られない。

編集:Windows用のen_US.utf8に相当するthis questionの回答を参照してください。

+0

うーん。この答えは正しい種類の領域にあるようです。どのようにあなたのロケールがutf8に設定されているのだろうと思っています...私がそれを試みると、setlocaleは失敗します。ここの文書:http://msdn.microsoft.com/en-us/library/x99tb11d.aspx(あなたがutf-8を検索した場合)は、utf-8を試しても失敗すると言います。たぶんMicrosoftの実装ではうまくいかないかもしれません。 –

+0

@ScottLanghamでは、ロケール名は標準化されておらず、Windowsでは何がサポートされているのかわかりませんが、UTF8ロケールではないUnicodeがないと驚いています。 – AProgrammer

+1

Windowsは「Unicode」ロケールをサポートしていません。すべての実装では、wchar_tのエンコーディングはロケールに依存しないため、ロケールのエンコーディングは狭いエンコーディングにのみ関連します。したがって、「Unicode」ロケールは本質的にUTF-8を必要とし、WindowsはUTF-8を使用するロケールを提供しません。 Windowsは、wchar_tエンコーディングとしてUTF-16を使用してUnicodeをサポートしています。 – bames53

5

私は通常、書式付きテキストを作成するのにstd::stringstreamを使用します。また、Windowsの関数を使ってエンコーディングを行う演算子を実装しました。

ostream & operator << (ostream &os, const wchar_t * str) 
{ 
    if ((str == 0) || (str[0] == L'\0')) 
    return os; 
    int new_size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, NULL, NULL, NULL); 
    if (new_size <= 0) 
    return os; 
    std::vector<char> buffer(new_size); 
    if (WideCharToMultiByte(CP_UTF8, 0, str, -1, &buffer[0], new_size, NULL, NULL) > 0) 
    os << &buffer[0]; 
    return os; 
} 

このコードはUTF-8に変換されます。その他の可能性については、WideCharToMultiByteをご確認ください。

+0

これを行う方法の良い例:) – jcoder

+0

@JohnB:ありがとう! :) – Naszta

関連する問題