文字化けについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
コダック

文字化けについて

#1

投稿記事 by コダック » 1週間前

現在Visual StudioにてC++とLuaでゲームを作成中なのですが、luaL_dofileでluaファイルの日本語を表示すると文字化けしてしまいます

色々と調べてはいるのですが混乱して理解が進みません

①Visual Studioで文字セットをUnicodeにした場合はエンコードはUTF-16が基本だそうです
これは今まさにソースコードが書かれているときにメモリへ書込み画面へ表示するときのエンコード方式の話なのでしょうか?

②VSでの通常の文字列定数(”例えばこれ”)はShift-JISコードだそうです。ソース・ファイルをUTF-8で保存しても文字列定数の文字エンコードはShift-JISなるというのですが、ここが意味がわかりません。エンコード方式を複数適用できるものなのでしょうか?
(参考2-4-1 https://theolizer.com/cpp-school1/cpp-school1-18/ )

③デバッグコンソール(コマンドプロンプト)ではShift-JISでエンコードされ表示されるみたいです。
そこで、簡単に

コード:

 
 printf("ohayou")
 printf("おはよう”)
 

という文字列定数をデバッグコンソールで表示することにしました
ソースファイルをUTF-8で保存し、プロジェクトプロパティのC/C++→コマンドラインに/source-charset:utf-8を追加したところ平仮名の方の「おはよう」も表示されました。
追加で

コード:

 int disp = luaL_dofile(L, "item.lua"); 
とし、Luaファイル(script.luaをUTF-8で保存)内

コード:

print('日本語ファイルだよ') 
を実行するとデバッグコンソールでluaファイルの「日本語ファイルだよ」が文字化けしました


文字コード技術入門を購入してこれから読んでいくところですが、理解の手助けをしていただけると幸いです。

Bull
記事: 137
登録日時: 5年前

Re: 文字化けについて

#2

投稿記事 by Bull » 1週間前

最初にお断りしておきますが、私は Lua については全く知りません。
Windows の一般的な文字コードについての概要についてだけですが、多少なりとも参考になれば幸いです。


Windows の内部コードは UTF-16 ですので、UTF-16 がネイティブな文字コードと言えます。
例えば、ウィンドウ(正確にはデバイスコンテキスト)に文字を描画するときに TextOut を、コンソールに文字を表示するときには WriteConsole という API を使用しますが、それぞれワイド文字 (Unicode) とマルチバイト文字 (Shift_Jis) の関数が用意されています。これは Visual Studio のプロジェクトの「文字セット」で切り替えます。あるいは直接 TextOutA/TextOutW、WriteConsoleA/WriteConsoleW を使い分けてもいいです。

ワイド文字用の関数には wchar_t*(あるいは wchar_t)を渡し、マルチバイト文字用の関数には char*(あるいは char)を渡します。
ソースコードでは TCHAR あるいは LPTSTR を使うことにより「文字コード」の切り替えで char/char* が
wchar_t/wchar_t* に切り替わります。



まずソースファイル(.cpp) と実行ファイル(.exe) の文字コードは別です。ソースファイルを UTF-8 で書いても、実行ファイルは Shift_Jis にできます。逆にソースファイルを Shift_Jis で書いて実行ファイルを UTF-8 にすることもできます。
ソースファイルの文字コードは "/source-charset:" で指定しますが、実行ファイルの文字コードは "/execution-charset:" で指定します。余談ですが、"/utf-8" で "/source-charset:utf-8" と "/execution-charset:utf-8" の両方を指定したと同じになります。
"/execution-charset:utf-8" を指定すればコンソールへの出力は UTF-8 で行われますが、そのままでは文字化けしてしまいます。
UTF-8 の文字列を表示するにはコンソールのコードページを 65001 にする必要があります。参考にしているサイトに書かれている通りchcp 65001 で変更できます。そのサイトには「まともには動作しません」と書かれていますが、すくなくとも Windows10 (1903) ならば表示には問題ありません。過去のバージョンではコードページを変えるにも一苦労だったのですが、できないわけではないです。
尚参考サイトに書かれている通り、u8"" の文字列を使用すれば、オプションを指定しなくても UTF-8 文字列が出力されます。

Luaファイルに関しては全くわかりませんが、もしかするとコンソールのコードページを UTF-8 (65001) にすれば文字化けしないかもしれません。

コダック

Re: 文字化けについて

#3

投稿記事 by コダック » 1週間前

回答ありがとうございます。

①WinAPIではMultiByteToWideChar等の関数を作成してやらなければいけないみたいですね…
TCHARも以前GDI+でゲーム作成した時は使用していて問題はなくて、今回本格的に2Dゲームの作成でぶち当たった壁なので本腰を入れて理解しないとダメそうです

②/source-charset:utf-8をセットして、UTF-8でソースを保存して実行するとデバッグコンソールでは平仮名の文字列は表示されますが、u8をつけると文字化けします
UTF-8に設定してu8でUTF-8で表示しろと再度命令してるのに文字化けする理由はお分かりになりますか?

よろしくお願いいたします。

Bull
記事: 137
登録日時: 5年前

Re: 文字化けについて

#4

投稿記事 by Bull » 1週間前


個人的にですが、Windows プログラムの文字コードは Unicode に統一する (wchar_tを使用する) のがいいじゃないかと思います。
ファイル入出力などで必要があれば、マルチバイト文字に変換する。そうすれば内部の処理がやりやすいのではないかと考えています。


デバッグコンソールとは何でしょうか? コマンドプロンプトのことだと思って解答をしてきましたが、もし別のものだとすると私の回答は意味のないものになります。
printf 関数を使っているので、Windows デスクトップのコンソールアプリケーションを想定して回答しています。

まず確認なんですが、Visual Studio と Windows のバージョンは何でしょうか?
Windows10 (1903) なら特に問題ないと思われますが、1809 以前の場合は、#1 の参考サイトに書かれている通りコンソール出力で文字化けする可能性があります。
また、Windows7 や Windows8 の場合ですと、コンソールのコードページを変更するさい、予めフォントを“MSゴシック”にしておかないと正常に表示ができません。コードページを変更してからではフォントの変更はできない(無効になる?)ようです。

当方の環境は Windows10 (1903) ですが、Visual Studio 2017、Visual Studio 2019 どちらでも、

コード:

#include <stdio.h>
int main(void)
{
	printf(u8"こんにちは\n");
}
は正常に表示されます。

なお、当方の環境でもコンソールのデフォルトのコードページはcp932 (Shift_JIS) なので、cp65001 (utf-8) に変更してからコマンドラインから実行しています。

プログラムの中からですと、SetConsoleOutputCP 関数を使用すればコードページを変更することができます。

コダック

Re: 文字化けについて

#5

投稿記事 by コダック » 1週間前

一度、Releaseでビルドし、コマンドプロンプトでchcp 65001でUTF-8表示指定してから作成された.exeを呼び出してみたところ、ちゃんと表示されました。


ただデバッグコンソールの方では文字化けするんですよねぇ…
u8つけようが、"/utf-8" や"/source-charset:utf-8" や "/execution-charset:utf-8"をコマンドラインで指定しても

コダック

Re: 文字化けについて

#6

投稿記事 by コダック » 1週間前

デバッグコンソールはVisual Studioでデバッグを行った際に表示される出力ウィンドウのことだと思っていたのですが違うようですね・・・

デバッグを行った際に表示されるコマンドプロンプトのことです

コダック

Re: 文字化けについて

#7

投稿記事 by コダック » 1週間前

Windows10(Win8.1からのアップグレード)
Visual Studio 2019
です。
戴いた回答を元にもう一度やってみます。

Bull
記事: 137
登録日時: 5年前

Re: 文字化けについて

#8

投稿記事 by Bull » 1週間前

デバッグコンソールの件は了解しました。Visual Studio のデバッガーから起動したとしてもコンソールには変わりはないので、それによって何かが変わることはないと思います。

コンソールのデフォルトのコードページは cp932 でこれを変更する方法ちょっとわかりません。コマンドラインで実行する場合はコードページを変更してから実行すればいいんですが、Visual Studio から実行したり、エクスプローラーから実行する場合はコードページは cp932 のままであろうと思われます。

UTF-8 の文字列を表示したかったら、ちょっと面倒ですがプログラム内部で表示する前にコードページを cp65001 に変更するしかないと思います。

次のようにすると Visual Studio から起動しても、文字化けせずに表示できます。

コード:

#ifdef   _WIN32
#include <Windows.h>
#endif
#include <stdio.h>
int main(void)
{
#ifdef _WIN32
	UINT cp = GetConsoleOutputCP();                     //現在のコードページを保存
	SetConsoleOutputCP(65001);                          //コードページをUTF-8に設定
#endif
	printf(u8"こんにちは\n");
#ifdef _WIN32
	SetConsoleOutputCP(cp);								//コードページを元に戻す
#endif
}

コダック

Re: 文字化けについて

#9

投稿記事 by コダック » 1週間前

試したみたことを報告させていただきます
※プロパティシートを読み込み、コマンドライン等の設定は既存のプロパティシートに追加しています

コード:

 
printf("ohayou\n");
printf( "おはよう\n");
printf(u8"おはよう\n");


①コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はShift-JIS
結果:u8をつけた方の平仮名の文字列定数は表示される

②コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:u8をつけた方の平仮名の文字列定数は文字化け

ここから、UTF-8で保存したLuaファイルを読み込み
print('日本語ファイルだよ')
VSのローカルWindowsデバッガーでデバッグ
③コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:Luaファイルから読み込んだ文字列は「蝠・刀縺ッ薬草縺繧」で文字化け

④コマンドラインに/execution-charset:utf-8を設定、ファイルの保存形式UTF-8(シグネチャなし)
結果:構文エラーなどのエラーが発生してコンパイル失敗

⑤コマンドラインに/utf-8を設定、ファイルの保存形式UTF-8(シグネチャなし)
結果:ASCIIと同じ割当て以外は文字化け

最後に、Releaseでビルドしたもの(Lua.exe)について
コマンドプロンプトを開きchcp 65001(UTF-8表示設定)と入力、ディレクトリ移動でLua.exe起動
⑥コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
ohayouとLuaファイルの日本語文字列「日本語ファイルだよ」が表示

⑦コマンドラインに/utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:全部正しく表示される

という具合になりました。

コダック

Re: 文字化けについて

#10

投稿記事 by コダック » 1週間前

#9のレスは抜けている情報が少々あるので無視してください。
申し訳ありません…

コダック

Re: 文字化けについて

#11

投稿記事 by コダック » 1週間前

試したみたことを報告させていただきます
※プロパティシートを読み込み、コマンドライン等の設定は既存のプロパティシートに追加しています

コード:

 
printf("ohayou\n");
printf( "おはよう\n");
printf(u8"おはよう\n");


①コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はShift-JIS
結果:u8おはようの文字列定数は表示される

②コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:u8おはようの文字列定数は文字化け

ここから、UTF-8で保存したLuaファイルを読み込み
print('日本語ファイルだよ')
VSのローカルWindowsデバッガーでデバッグ
③コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:Luaファイルから読み込んだ文字列は「蝠・刀縺ッ薬草縺繧」で文字化け
   u8おはようの文字列定数は文字化け

④コマンドラインに/execution-charset:utf-8を設定、ファイルの保存形式UTF-8(シグネチャなし)
結果:構文エラーなどのエラーが発生してコンパイル失敗

⑤コマンドラインに/utf-8を設定、ファイルの保存形式UTF-8(シグネチャなし)
結果:ASCIIと同じ割当て以外は文字化けでohayouだけの表示

最後に、Releaseでビルドしたもの(Lua.exe)について
コマンドプロンプトを開きchcp 65001(UTF-8表示設定)と入力、ディレクトリ移動でLua.exe起動
⑥コマンドラインに/source-charset:utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:おはようは文字化け、他は正しく表示される

⑦コマンドラインに/utf-8を設定、ファイルの保存形式はUTF-8(シグネチャなし)
結果:全部正しく表示される

という具合になりました。




VSから起動しても文字化けに対処できる方法を教えていただきありがとうございます!
自分でも⑦の結果からコンソール表示を常にUTF-8にする方法を探して試したのが以下のサイトに載っていたことです

(参考:https://thinkridge.com/modules/xpwiki/? ... 8%E7%A4%BA)

stl.natvisのアクセス許可を得て
VS2013も書かれている通りにやってみましたがダメでした…




・/source-charset:utf-8は「プログラムのソーステキストを、コンパイル前のプリプロセスフェーズへの入力として使用される内部表現として解釈するために使用されるエンコーディングです」とあるので、VSでコードを書いてるときはUTF-16ということでいいのでしょうか?
(参考:https://docs.microsoft.com/ja-jp/cpp/bu ... ew=vs-2019)


・実行ファイルの文字コードを指定する/execution-charset:utf-8だとエラーになるのはどうしてなのでしょうか?
エラーを見るにコード変換で他の文字に扱われているらしく「;」や「)」がない、リテラルサフィックスが無効等が出てます。
VSでUTF-16やShift-JISで記述していようがファイル保存で指定したエンコード形式、実行ファイルなどでは内部でエンコードするがそれに失敗しているということでしょうか?




プリプロセスの話など、未だに中でどのようなことが行われているのか完全に把握できておりません。

よろしくお願いします。

Bull
記事: 137
登録日時: 5年前

Re: 文字化けについて

#12

投稿記事 by Bull » 5日前

オフトピック
台風の影響もあって、暫くネットにつなぐことができませんでした。
返信が遅くなり申し訳ありません。

以前も書いたと思うのですが、ソースファイル (.c/cpp) の文字コードと実行ファイル (.exe) の文字コード(エンコード)は別です。
ソースコードを UTF-8 で書いて、Shift_JIS の実行ファイルを作成することも、逆に Shift_JIS で ソースコードを書いて UTF-8 の実行ファイルを作ることも可能です。
コンパイラーの内部の構造について詳細に把握しているわけではありませんが、おそらくソースコードを一旦内部コード(おそらく UTF-16)に変換して処理しているものと推測しています。

ソースコードの文字コードを正しく認識していないと、正しく変換ができないので、結果として実行ファイルの文字コードの正しくないと言うことになります。

Visual C++ のコンパイラーは "/source-charset" オプション が指定されていない場合は文字コードをシグネチャ(バイト順マーク/BOM)により自動判定します。シグネチャが無ければ Shift_JIS と見なします。"/source-charset" オプション が指定されていればそれに従います。

ソースファイルの文字コードか何がいいのかについては、正解はないと思います。個人的な感覚では Windows のみで使用して、全ての文字を Shift_JIS の範囲内で表せるならば Shift_JIS でもいいのですが、他の OS のことも考えると UTF-8 がいいのではないかと考えています。(信憑性のあるデータかはわかりませんが、今後のテキストファイルは UTF-8 が主流になるという記事も読んだことがあります)
UTF-16 でソースファイルやテキストファイルを作るのは多少抵抗があります。

Visual C++ でコンパイルすることが前提ならば、シグネチャはつけておいた方がいいです。シグネチャなしで、オプションなしでコンパイルするとコンパイラが Shift_JIS と認識するので文字化けの原因になります。
gcc ではかなり以前のバージョンからソースコードの文字コードはデフォルトで UTF-8 でした。以前はシグネチャがあると正しくコンパイルできなかったのですが、最近のものはシグネチャがあっても問題なくコンパイルできます。
そうゆうこともあってソースコードの文字コードは個人的には UTF-8(シグネチャあり)をおすすめします。

コンパイラーがソースコードの文字コードを正しく認識していれば実行ファイルの文字コードも正しいはずです。実行ファイルの文字コードというのは、

コード:

#include <stdio.h>
int main(void)
{
	char *str = "こんにちは";
	printf("%s\n", str);
}
このようなソースをビルドすると、文字リテラルの "こんにちは" が実行ファイルに書き込まれます。その時に文字コード(エンコード)がなんであるかということです。
バイナリーデータで表すと、Shift_JIS の場合は 0x82 0xB1 0x82 0xF1 0x82 0xC9 0x82 0xBF 0x82 0xCD で、UTF-8 では 0xE3 0x81 0x93 0xE3 0x82 0x93 0xE3 0x81 0xAB 0xE3 0x81 0xA1 0xE3 0x81 0xAF となります。
printf 関数は特別な変換を行いませんので、そのままコンソールに出力されます。
文字を表示するのはコンソールの仕事ですが、コードページが正しければ正常に表示されるはずです。

コダック

Re: 文字化けについて

#13

投稿記事 by コダック » 3日前

Bullさん、返信遅くなり申し訳ありません。

段々と内部処理も分かってきました
子細に述べて戴き本当にありがとうございました

文字コードは面倒そうで敬遠していたのですが、本格的にゲームを制作するにあたり避けては通れなかったので助かりました
それでは失礼します。

返信

“C言語何でも質問掲示板” へ戻る