次のサンプルプログラムについて考えてみます。
#include <cstdio>
#include <cwchar>
#include <string>
int main()
{
std::string narrowstr = "narrow";
std::wstring widestr = L"wide";
printf("1 %s \n", narrowstr.c_str());
printf("2 %ls \n", widestr.c_str());
wprintf(L"3 %s \n", narrowstr.c_str());
wprintf(L"4 %ls \n", widestr.c_str());
return 0;
}
この出力は次のとおりです。
1 narrow
2 wide
不思議なんだけど:
あなたがする必要があります:
_wprintf(L"3 %hs \n", narrowstr.c_str());
wprintf(L"4 %s \n", widestr.c_str());
_
どうして? printf
の場合、%sは、narrow-char-stringを表します。 wprintf
の場合、%lsは広いと言います。
ただし、wprintf
の場合、%sは広いことを意味し、-%lsはそれ自体が広いことを意味します。 %hsは狭くなります(両方とも)。 printf
の場合、%sは、この方法では単に%hsを意味します
VC++/Windowsでは、_%S
_(大文字のS)を使用すると、効果が逆になります。したがって、printf("%S")
は幅が広く、wprintf("%S")
は幅が狭いことを意味します。これは__tprintf
_に役立ちます。
Cストリームを使用していることに注意してください。 Cストリームには、「向き」と呼ばれる非常に特殊な品質があります。ストリームは、無指向、ワイド、ナローのいずれかです。方向は、特定のストリームに対して行われる最初の出力によって決定されます(C I/Oストリームの概要については http://en.cppreference.com/w/cpp/io/c を参照)
あなたの場合、stdout
は無指向で始まり、最初のprintf
を実行することで、それを狭く設定しています。狭くなったら狭くなり、wprintf
は失敗します(戻りコードを確認してください!)。 Cストリームを変更する唯一の方法は、それをfreopen
することです。これはstdoutでは十分に機能しません。そのため、3と4は印刷されませんでした。
1と3の違いは、1はナロー文字列変換指定子%sを使用するナロー出力関数です。char配列からバイトを読み取り、バイトストリームにバイトを送信します。 3は、幅の狭い文字列変換指定子%sを持つワイド出力関数です。最初に文字配列からバイトを読み取り、mbtowc
sバイトを_wchar_t
_ sに読み込み、次に_wchar_t
_ sをワイドストリームに送信します。次に、それらをwctomb
sバイトまたはマルチバイトシーケンスに変換し、write
を使用して標準出力にプッシュします。
最後に、widestrがutf16にある場合、Windowsを使用している必要があり、すべてのベットがオフになっています。 ASCIIを超えるものに対するサポートはほとんどありません。WinAPIを提供して使用することもできます(Unicodeについては、標準のC++ 11を使用して、さらにはマジックワード_setmode(_fileno(stdout), _O_U16TEXT);
を含むこのC出力、十分に議論されています)
質問の1と2に対する回答はドキュメントにあります。ドキュメントの適切なセットで十分です。 cppreference はとても良いと彼らは言う。
3に関しては、言語標準は文字列の特定のエンコーディング、または特定のサイズのwchar_t
を指定していません。適切な言語ではなく、実装のドキュメントを参照する必要があります(実装に依存するコードを記述することはほとんどお勧めできません)。