質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

7944閲覧

C++ 文字化けしてしまう

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/11/03 02:02

編集2019/11/03 02:42

以下のコードで出力すると日本語が文字化けしてしまいます。
使用しているコードエディタはVisual Codeですが、Shift JISに変更してから書いているので、どうして文字化けするのか分かりません。
どなたかご教授願えると幸いです。
よろしくお願いします。

C++

1#include<iostream> 2using namespace std; 3 4int main() 5{ 6 cout<<"サンプル"<<endl; 7 cout<<"Example"<<endl; 8 9 return 0; 10}

shell

1Tv 2Example

[コンパイラ]
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[OS]
Windows Subsystem for Linux
[実行した環境]
ターミナル内
[環境内の文字コード]
不明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2019/11/03 02:12

コンパイラ、OS、実行した環境(エディタ内なのか、ターミナルで起動したのか)、その環境の文字コード(意味がわからない場合は、文字コードは不明)を質問文に追記してください。文字化けは複数の要因が絡み合うため、これらの情報が無いと、どうやって対処すれば良いのか回答することは難しいです。
退会済みユーザー

退会済みユーザー

2019/11/03 02:33

ありがとうございます。
guest

回答2

0

ソースコードはUTF-8のままにして、WSL上でコンパイルしてください。


【解説】(凄く長い)

C++での文字列リテラル "~" という表記はconst char[N]型の ナローマルチバイト文字列リテラル(narrow multibyte string literal) です。ナローマルチバイト文字列とはシングルバイト文字列(ASCII等)やマルチバイト文字列(UTF-8、Shift_JIS等)のことを意味します。バイナリ上でどのエンコードになるのかは環境依存であり、環境のデフォルトまたはコンパイラオプションによって決定されます。

環境のデフォルトはOSやロケール設定によって異なります。Windowsであれば、デフォルトはANSIと言われる現在のロケールに合わせたASCII互換な文字コードです。日本語ロケールの場合は Windows-31J というShift_JISの亜種(Shift_JISとは一部が異なる)であり、Windows内部では932というコードページが割り当てられています(そのため、CP932、MS932とも言われます)。最新のmacOSやLinuxではUTF-8になっています(日本語ロケール未設定の場合はen_US.UTF-8で、日本語ロケールにするとja_JP.UTF-8になるという形がほとんどです)。WSL上のUbuntuの場合はLinuxとして設定されるため、UTF-8がデフォルトになります。Windows側が日本語ロケールであれば、環境変数LANGja_JP.UTF-8になっている事でも確認できるはずです。

おっとここで、先に進む前にターミナルの話をしなければなりません。ConEmuとかを使っていない場合、WSLのターミナル画面はコマンドプロンプトやPowerShellと同じWindowsのコンソール機能を使っています。このコンソール自体は複数の文字コードに対応しています。ウィンドウのバーを右クリックして「プロパティ」を開いてくみてください。「オプション」タグに「現在のコードページ」の所に現在のコードページ(Windowsで文字コードを識別するための番号)が表示されていることでしょう。日本語環境であれば、932 (ANSI/OEM - 日本語 Shift-JIS)65001 (UTF-8)の何れかです。Windows標準のコマンドプロンプトやPowerShellは932になります(chcpコマンドで切り替え可能)が、WSL上のUbuntuを立ち上げたときは自動的に65001に切り替わります。これは932なコマンドプロンプト上でbashとした場合も同様です。先程、WSL上のUbuntuはUTF-8になっていると言いましたが、このコンソール機能でもUTF-8となっているため、日本語のメッセージなどが文字化けせずに表示されるようになっています。

話を戻しましょう。UbuntuではC++上の"~"という文字列リテラルはUTF-8である。UbuntuのターミナルもUTF-8である。であれば、文字化けするのはおかしいはずです。では何がいけなかったのか?それはソースコードの文字コードとコンパイラが認識する文字コードが一致していなかったからです。

ちょっとだけ変えた下のコードを同じようにShift_JISで保存してコンパイルしようとしてみてください。

C++

1#include<iostream> 2using namespace std; 3 4int main() 5{ 6 cout<<"サンプル表"<<endl; 7 cout<<"Example"<<endl; 8 9 return 0; 10}

エラーになりましたね?このコードがShift_JISであった場合、UTF-8として解釈すると文法エラーになってしまいます。「表」という文字はShift_JISで95 5Cです。これをUTF-8で解釈すると5Cが\と解釈され、後ろに続く"をエスケープしてしまい、文字列が終了せず、改行まで進んでしまうからです。どうしたらこれを防げるのか…というと、実は先程の話と同じです。ソースコードがどの文字コードであるとして読み込むかは、環境のデフォルトまたはコンパイラオプションで決定されます。ほとんどの場合は、先程と同じものがデフォルトになります。

では、上のコードをコンパイル出来るようにオプションを加えてみましょう。次のような形で-finput-charset=cp932オプションを加えてみてください(sjisとかでもできそうな気がするのですが、手元の環境ではcp932以外だとうまくいきませんでした)。

g++ -finput-charset=cp932 {{ソースコードファイル名}}

うまくコンパイル出来ましたね。実際に実行してみてください。おぉっと、文字化けしませんでしたね。ソースコードはShfit_JISで、環境はUTF-8のはずです。なのにうまくいきました。何故なんでしょうか?

ここまでちゃんと読んでいればわかるはずです。ソースコードの文字コードとコンパイルによって出力されたバイナリに埋め込まれた文字コードは関係が無いと言うことです。それぞれ別々に管理されており、環境のデフォルトまたはコンパイラオプションによって決定されます。コンパイル後の文字コードは、GCCであれば-fexec-charsetで指定可能です。このオプションはそれぞれバラバラに設定でき、文字コードの変換が行われることになります。

さて、最初の文字化けの話に戻ります。文字化けしたのはShift_JISのコードをUTF-8として解釈したからでした。この処理では、UTF-8として解釈できる文字はそのまま、解釈できない文字はREPLACEMENT CHARACTER(U+FFFD)に置き換えて、バイナリに埋め込みます(この置き換えはiconvの動作に依存したものと思われます)。そして実行される環境もUTF-8であるため、解釈できた一部の文字Tvと解釈できずに置き換わられ�が表示されるというわけです。

文字化けしないようにする方法は次の二つです。

  1. ソースコードの文字コードをコンパイル時に指定する。
  2. 環境のデフォルトにソースコードの文字コードを合わせる。

最初のは既に示しましたが、毎回毎回オプションを付けるのは面倒ですので、2.の方法、つまり、UTF-8として保存する方が良いでしょう。

なお、Visual Studioでもコンパイルしたいとか、そういった移植性のあるコードを書きたい場合はまた別の話です。解説するのが嫌になるぐらいめんどくさい話になるので、移植性をとるならソースコードはASCIIのみにするのが一番楽です。

【おまけ】

C++11からu8"~"という表現ができるようになりました。このu8付きの文字列リテラルは、環境やコンパイルオプションによらず、バイナリ上ではUTF-8として存在することになります。例えば、Windows日本語環境において、各文字列リテラルは次のようになります。

C++

1"これはWindows-31J"; 2u8"これはUTF-8"; 3L"これはUTF-16"; // Windowsでのワイド文字列はUTF-16を採用している 4u"これはUTF-16"; 5U"これはUTF-32";

※ ソースコードの文字コードとコンパイラに認識している文字コードが一緒であれば、ソースコードの文字コードに関係無く、こうなります。

"~"u8"~"の文字コードが異なるのはWindowsぐらいしかありませんが、コマンドプロンプトで表示させるエラーメッセージはWindows-31Jだけど内部での各テキストの扱いは全てUTF-8にしたいという時に便利かも知れません。

参考: 文字列リテラル - cppreference.com

投稿2019/11/03 06:32

編集2019/11/03 14:24
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こんにちは。

使用しているコードエディタはVisual Codeですが、Shift JISに変更してから書いている

WSLは使っていないので外しているかもしれませんが、恐らく原因は上記です。
Linuxは基本的にデフォルトは全てUTF-8に統一されています。ソース・コードの文字コードもUTF-8と仮定します。(変更は可能ですがオプション指定が必要)
なのにShift-JISでソースを書いているからだろうと思います。ソースをUTF-8で書けば恐らく化けないだろうと思います。

投稿2019/11/03 03:49

編集2019/11/03 03:51
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問