• ベストアンサー

wstringの主力

wstring (または wchar_t)の出力がうまくいかず困っています。 基本的な質問になるかと思いますがよろしくお願いします。 #include <string> #include <wchar.h> using namespace std; int main() {  wstring str = L"test";  wprintf(L"%s \n", str.c_str());//(1)  wprintf(L"%s \n", L"test");//(2)  wprintf(L"test \n");//(3)  // cout << str <<endl; //(4)  cout << str.c_str() <<endl;//(5) } 出力結果 (1) t (2) t (3) test (4) コンパイルエラー (5) 望むのは当然(3)の出力です。 web上で(1)や(4)のような記述はみかけたのですが、(4)に関してはなぜコンパイルエラーになるかもわからず。。 os linux. gcc 4.1.1

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

> wprintf(L"%s \n", str.c_str());//(1) > wprintf(L"%s \n", L"test");//(2) c_strはワイド文字列のデータ本体をwchar_t *で返すのみ。"test\0"を返す訳ではない。 この場合、(1)も(2)も  wprintf(L"%s \n", (char *)((wchar_t *)"t\0e\0s\0t\0\0\0")); に同じ。つまり  wprintf(L"%s \n", "t"); と書いたのと同じである。 書式sにwchar_t型文字列を引数に与える場合は、書式sにl修飾子を付加する事。 (1)、(2)は以下のようにすると正常に動作する筈。  wprintf(L"%ls \n", str.c_str());//(1)  wprintf(L"%ls \n", L"test");//(2) > wprintf(L"test \n");//(3) については解説不要。 > // cout << str <<endl; //(4) #include <iostream>を記述する位置を適切な位置にしない限り、coutの実体であるstreambufの挿入演算子(<<)は、char *しか受けつけず、コンパイルエラーとなる。 > cout << str.c_str() <<endl;//(5) c_strはワイド文字列のデータ本体をwchar_t *で返すのみ。"test\0"を返す訳ではない。つまり、  cout << "t\0e\0s\0t\0\0\0" <<endl;//(5) と書いたのと等しく、更に言えば  cout << "t" <<endl;//(5) と等しい。

________j_
質問者

お礼

詳しいご解説ありがとうございます。 質問のソースコードでうまく行かない理由がよくわかりました。 さっそくwprintfにてフォーマット指定子%lsを使って表示を試みたのですが、日本語を含む場合の出力で文字化けしてしまいました。 ソースコード UTF8 端末のエンコード UTF8 で統一しており、perl で print "testてすと"; 等するとちゃんと端末上に文字化けせずに表示されるのですが・・。

________j_
質問者

補足

#2さんの補足欄のさらに補足です。 あちこち書く場所が飛んでしまって申し訳ありません。 > 文字化けは、端末のエンコードをEUC-JPに変更したら直りました。 半分嘘でした。 どうやら、/etc/locale.gen の ja_JP.EUC-JP のコメントアウトをはずしてlocale-gen した場合にそうなったようです。 ja_JP.UTF-8 の部分だけコメントアウトしてlocale-genし、 コード中にlocale("japanese") を locale("ja_JP.UTF-8") に変更したところ、例外は発生しなくなりました。が、やはり wcout << L"testテスト" の表示(端末のエンコード UTF8) が test??? になってしまいます。端末のエンコードの問題ではなさそうです。

その他の回答 (1)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

(1)~(3)に関しては、#1の方の回答のとおりです。 (4)がコンパイルエラーになる理由ですが、std::coutすなわちstd::basic_ostream<char, std::char_traits<char> >型に対して多重定義されている<<の右オペランドは、const std::basic_string<char, std::char_traits<char>, std::allocator>&型(cons std::string&)であって、const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator>&型(const std::wstring&)ではありません。多重定義されていないわけですから、当然エラーになります。 (5)に関しても同様で、右オペランドにconst char*を取る<<演算子は多重定義されていますが、const wchar_t*を取るものは課定義されていないため、const void*に変換されてしまいます。(表示されないのは変です。アドレス値が出るはずです。ただし、変なファセットを持つロケールをimbueしていない場合)

________j_
質問者

お礼

ご回答ありがとうございます。 コンパイルエラーの理由、よくわかりました。 > 表示されないのは変です。アドレス値が出るはずです については再度試してみましたがやはり何も表示されませんでした。 ロケール・imbueをキーワードに色々検索し、以下のページを参考に #include <string> #include <iostream> #include <locale> using std::wstring; using std::wcout; using std::endl; using std::locale; int main() {  wstring wstr = L"testテスト";  wprintf(L"%i \n", wstr.length());  wprintf(L"%ls \n", wstr.c_str());    wcout.imbue(locale("japanese"));  wcout << wstr <<endl;  wcout << L"testてすと" << endl; } をコンパイルして実行したところ、 7 test??? test??? test??? と文字化けを起こしてしまうのですが、原因がどうもわかりません。 端末の文字エンコードは UTF-8,ソースコードもUTF-8です。 また、このプログラムを異なる計算機(OS,gccのバージョンは同じです)で実行してみたところ、 terminate called after throwing an instance of 'std::runtime_error' what(): locale::facet::_S_create_c_locale name not valid Aborted という例外を吐いてアボートしてしまいます。 環境がほとんど同じだけに、原因がわからずここでも躓いています。 locale("japanese") が通るように何か(環境の設定,ライブラリ等)他にしなければいけないことがあるのでしょうか?

________j_
質問者

補足

お礼欄の補足です。 > 再度試してみましたがやはり何も表示されませんでした。 は wprintf した後の cout が表示されないというよく分らない現象のせいで、wprintfを全てコメントアウトしたら表示されました。 文字化けは、端末のエンコードをEUC-JPに変更したら直りました。 本当はUTF-8で吐いてほしいのですが・・ そこで、UNIXの話になってしまうのですが、locale("japanese")を含むプログラムが実行可能であったマシンの、/etc/locale.gen ja_JP.UTF-8 UTF-8 をコメントアウトし、 # locale-gen したら terminate called after throwing an instance of 'std::runtime_error' what(): locale::facet::_S_create_c_locale name not valid Aborted が表示されるようになってしまいました。現在その原因の調査中です。

関連するQ&A

  • std::wstringの継承

    #include<iostream> #include<string> #include <stdlib.h> #include <locale.h> #include <boost/lexical_cast.hpp> using boost::lexical_cast; using namespace std; VisualC++2008ExpressEditionで文字や数字を簡単に扱えるクラスを今作ろうとしていて以下のように作ってみました。 class multiString:public std::wstring{ public:   multiString(const wchar_t *ws){     /* multiString class自体に代入 */   } }; しかし、このwchar_tをクラスに代入する処理として、 multiString(const wchar_t *s)std::wstring(s); とすると、「error C2082: 仮パラメータ 's' が再定義されました。」となりますし、 multiString(const wchar_t *s)*this=s; とすると、例外が発生してしまします。 wstringだったら、簡単に代入処理として出来るのですが、継承した場合はどの様に実装すればいいのでしょうか? 宜しくお願いします。

  • ワイド文字(列)について

    ワイド文字(列)について質問です。 printf()などより、wprintf()などのワイド文字を扱える関数を 使おうと思っているのですが、うまく表示されません。 何が原因なのでしょうか? ソースです。 #include <stdio.h> int main(void) { wchar_t *data = L"かきくけこ"; wprintf(L"あいうえお\n"); wprintf(L"%s\n", data); return (0); } wprintf(L"%s\n", data);は表示はされるのですが、 「?」になります。 環境 XP Visual Studio 2005

  • プログラムの動作の仕方

    この下のプログラムは、WRITE <ファイル名>をコマンド行で入力すると、動作するプログラムなのですが、この通りにWRITE <test>としてもできません。 やり方を教えてください. #include <iostream> #include <fstream> using namespace std; int main(int argc,char *argv[]) { if(argc!=2){ cout << "使い方:WRITE<ファイル名>" << endl; return 1; } ofstream out(argv[1]); //出力ファイル if(!out){ cout << "出力ファイルが開けません" << endl; return 1; } char str[80]; cout << "文字列をディスクに書き込み、$で停止します" << endl; do{ cout << ": "; cin >> str; out << str << endl; }while(*str!='$'); out.close(); return 0; } お願いします。

  • C++

    今、下のようなプログラムを作っています #include <iostream> #include <iostream> using namespace std; int i=0, c=0, n; char str[10]; class X16karax10{ //16進から10進ヘ public: void keisan(); }; void X16karax10::keisan(void){ cout<<"16進を入力して下さい"<<endl; cout<<"英数字は大文字で入力してください(F→○ f→×)" <<endl; scanf("%s",str); while(str[i] != '\0'){ n = n * 0x10; c = str[i++]; if((c >= '0') && (c <= '9')){ n += c - '0'; } else if((c >= 'A') && (c <= 'F')){ n += c - 'A' + 10; } } cout<<("%d\n",n)<<"です\n"<<endl; } int main(){ for(i=0; ; i++){ X16karax10 p; p.keisan(); } } 16進を十進に変えるものなのですがreturn 0を使うと「X16karax10::keisan()' は値を返せない」と、でてしまうのですがどうしたらよいでしょうか?

  • STLのwstring型から BSTR型 への変換

    // STLのwstring型から BSTR型 への変換てこんな感じでいいのでしょうか? #pragma warning(push,3) #include <string> #pragma warning(pop) #include <Windows.h> void main(void) {  std::wstring sString1 = L"This is STL_wstring";  std::wstring sString2;  BSTR sWork1 = ::SysAllocString(L"This is BSTR\n");  BSTR sWork2;  sString2 = sWork1;  sWork2 = ::SysAllocString(sString1.c_str()); // ここ  ::SysFreeString(sWork1);  ::SysFreeString(sWork2); }

  • c++テンプレート関数名

    #include <iostream> #include <string> using namespace std; template <class T> T maxdt std(T a,T b){ if (a>b) return a;else return b; } int main (){ int id1,id2,n1 = 1000,n2 = 2000; double ddt; string sdt,s1 = "abcd",s2 = "jklm"; id1 = maxdt(n1,n2); id2 = maxdt(3000,4000); ddt =maxdt (55.55,66.66); sdt = maxdt(s1,s2); cout << "id1" << id1 <<endl; cout << "id2" << id2 <<endl; cout << "ddt" << ddt <<endl; cout << "sdt" << sdt <<endl; return 0; } というプログラムが例題であり、僕は横着をしてmaxdtをmaxという名前としてプログラムを作ったところ、 オーバーロード関数の呼び出しがあいまいです。 というエラーが表示されコンパイルできませんでした。 環境はubuntu 12.04,gcc 4.6.3 g++でコンパイルしました。 ググってもテンプレート関数の名前の付け方に規則は存在していないようなのですが、 これは直前に作ったプログラムの影響でしょうか?(maxという関数を作っていたので) それとも別の規則が存在したりするのでしょうか?

  • wstringについて

    以下のプログラムを実行すると「Abnormal program termination」となってしまいます。 何故なのでしょうか? どこか間違っているところがあるのでしょうか? #include <iostream> #include <string> int main(void) { std::wstring ws = L"文字列"; std::wcout.imbue(std::locale("japanese")); std::wcout << ws << std::endl; return 0; } 環境はWindowsXP/Borland C++ Compiler 5.5です。 よろしくお願いします。

  • ofstream::getがおかしい!

    ofstream::getの動作がおかしいのです #include <string> #include <iostream> #include <fstream> using namespace std; void main(void) { ifstream ifs; ofstream ofs; string str; char c; str="abc"; cout<<"before str: "<<str<<endl<<endl; ofs.open("gomi");ofs<<str;ofs.close(); ifs.open("gomi");for(str="";ifs.eof()==0;str+=c)ifs.get(c);ifs.close(); cout<<"after str: "<<str<<endl<<endl; } の結果が before str: abc after str: abcc になります 最後のcは何でつくのでしょうか? 回避する方法を教えてください

  • char型配列について

    基本的なことですが、 char str[5]="Hello"; --> str[0]='H' str[1]='e' str[2]='l' str[3]='l' str[4]='o' str[5]='\0' では、ないのでしょうか? エラーが出ます。 //error C2117: 'str' : 指定された配列には、初期化子が多すぎます。 char str[6]="Hello"; では、コンパイルできます。 ---------------------------------- また、 #include<iostream> using namespace std; int main() { char str[6]="Hello"; cout << str << endl; for(int i=0;i<7;i++) { cout << "i=" << str[i]; if(str[i]=='\0'){cout << " NULL" << endl;} else{cout << endl;} } getchar();return 0; } ----------------------------------------------- とすると、 Hello i=H i=e i=l i=l i=o i= NULL <--ここで、NULLなら、 i=フ <--このぶんは、いらないと思うのですが、、、 となります。 str[6] i=6 は、何を意味するのでしょうか? Visual C++ NET を使用しています。 よろしくお願いします。

  • macのXcodeにおけるcinについて

    現在macOSXver10.4.11のXcode2.4.1を用いて C++言語の勉強をしています。 以下のソースをコンパイルしようとしてますが「std::cin >> str1;」の行で「error: no match for 'operator>>' in 'std::cin >> str1;'」と出てコンパイルに失敗します。 原因が分かる方がいればご教授願います。 #include <iostream> #include <stdio.h> int main (void) { char *str1[32], *str2[32]; std::cout << "何か入力して下さい ==>"; std::cin >> str1; std::cout << "あなたは" << str1 << "と入力しましたね。" << std::endl; printf("何か入力してください。==>"); scanf("%s",str2); printf("あなたは、%sと入力しましたね。\n",str2); return 0; } 初歩的な質問ですみませんがご回答の程よろしくお願い致します。

専門家に質問してみよう