今回の記事は自分が右往左往したVisualStudio/C++環境下においての文字コード・文字型・プレフィックスの関係性について、ChatGPTにまとめてもらったものです。
文字関係の問題に悩む人の一助になればと思います。どうぞ。
この記事では、Visual Studio の「Unicode / マルチバイト文字セット」と、C++ の文字型・文字列リテラル(プレフィックス)・エンコーディングが、どう噛み合っているのかを整理します。
1. 「Unicode文字」と「マルチバイト文字」の説明(Visual Studio の設定)
Unicode文字セット
Windows API を含む多くの現代的な Windows 開発で標準的な設定です。内部的には「ワイド文字(wchar_t)」を使う流儀になり、Win32 API も基本的に ...W(Wide)側を使うことになります。
マルチバイト文字セット
いわゆる「ANSI(A)」系APIや、Shift-JIS/CP932 前提の資産に寄せた設定です。TCHAR が char 側に寄り、文字列が OS のコードページ(日本語Windowsなら CP932)依存になりやすくなります。
2. C++ における文字型の解説(型ごと)
char
1バイトの文字型です。std::string の要素型でもあり、実務では「文字」よりも「バイト列の器」として使われることが多いです。中身が UTF-8 なのか Shift-JIS なのかは運用ルール次第です。
signed char / unsigned char
同じく1バイトですが、符号付き/符号なしが明確です。バイナリ処理やバイト配列として扱いたいときに便利で、文字コード用途というより「生のデータ」用途で登場します。
wchar_t
ワイド文字型です。Windows では多くの場合 16bit(UTF-16 のコードユニットとして運用されがち)で、Win32 API(W系)との相性が良いです。ただし規格上「必ずUTF-16」という保証ではありません。
char16_t
16bit固定の文字型で、UTF-16 のコードユニット列を表現するための型です。プラットフォーム差が少なく、UTF-16 を明示したいときに使います。
char32_t
32bit固定の文字型で、UTF-32 を表現するための型です。コードポイント単位の処理がしやすい反面、サイズは大きめです。
char8_t(C++20)
UTF-8 用の文字型です。u8"..." リテラルの型が char8_t[] になり、std::u8string との親和性が高いです。一方で std::string(char)と混ぜると型変換が必要になることがあります。
3. 文字列リテラルのプレフィックス(例つき)
C++ の「プレフィックス」は、主に“リテラルの型”を変えます(Shift-JISなど特定コードページを直接指定する機能ではありません)。
"text":const char[]L"text":const wchar_t[]u8"text":const char8_t[](C++20以降)u"text":const char16_t[]U"text":const char32_t[]
また、Raw文字列(エスケープを気にしない)も組み合わせ可能です:
R"(C:\path\file.txt)"u8R"(改行\nもそのまま)"
4. それぞれがどう関係しているか(混乱ポイントの整理)
ここが一番大事です。
4-1. 「Visual Studioの文字セット」は何を変える?
Visual Studio の「Unicode / マルチバイト文字セット」は、主に Windows API 呼び出しや TCHAR 系の挙動に影響します。
- Unicode文字セット:
TCHAR→wchar_t、MessageBox→MessageBoxWのように Wide 側へ寄る - マルチバイト文字セット:
TCHAR→char、MessageBox→MessageBoxAのように ANSI 側へ寄る
4-2. 「ソースコードの保存形式(UTF-8など)」は別レイヤ
.cpp/.h を UTF-8(BOMなし)で保存し、/utf-8 を付けるのは、コンパイラがソースや文字リテラルをどう解釈するかに影響します。
つまり、
- 文字セット(Unicode/マルチバイト)= “実行時の文字列型やAPI側の方針”
- ソースの文字コード(UTF-8など)= “ソースをどう読むか”
この2つは別物なので、混ぜると「どっちの話だっけ?」となりやすいです。
4-3. Shift-JIS はプレフィックスでは作れない
L"" や u8"" は Unicode系のリテラルを作る仕組みです。Shift-JIS(CP932)は型ではなくコードページ変換の結果なので、必要な場合は 変換関数で std::string(バイト列)として生成するのが一般的です。
5. どういう条件で使い分けるべきか(おすすめ運用)
5-1. Windows中心・今後も育てるプロジェクト(おすすめ)
- Visual Studio:Unicode文字セット
- ソース:UTF-8(BOMなし) +
/utf-8 - 方針:普段は
std::stringを UTF-8 として運用し、Windows API境界だけstd::wstring(UTF-16相当)へ変換
この運用は、教材的な std::string の感覚を残しつつ、Unicodeにも強くできます。
5-2. レガシー資産が Shift-JIS 前提で、短期で動かしたい
- 既存のSJISテキスト(CSV/辞書/台詞)が大量にある
- 古いツールや資産がSJIS前提
この場合でも「全体SJIS化」より、
- I/O(読み込み/書き出し)だけSJIS
- 内部はUTF-8/UTF-16へ寄せる
の方が事故が少ないことが多いです。
5-3. ゲームで「1文字ずつ表示」などをしたい場合
UTF-8の std::string を使う場合、1バイト=1文字 ではないため、
- UTF-8をデコードして「コードポイント」単位で進める(軽量)
- さらに厳密にやるなら「グラフェム境界」(ICUなど)で進める
といった方針が必要です。
最短まとめ(迷ったらこれ)
- Unicode文字セットを選ぶ(Windows開発の基本)
- ソースは **UTF-8(BOMなし)**で統一し、必要なら
/utf-8 std::stringは “UTF-8の器” と割り切って使う- Windows APIやファイルパスなど OS 境界だけ
std::wstringに変換する - Shift-JIS は「プレフィックス」ではなく「変換で必要なときだけ作る」
付録:Visual Studioで「新規/保存ファイルの既定エンコーディング」をUTF-8(BOMなし)にする方法
Visual Studioでは、ファイルの既定保存エンコーディングを指定できます。Visual Studio 2022 v17.13以降では、IDEの設定として「既定の保存エンコーディング」を明示的に選べます。
方法A:Visual Studioのオプションで既定エンコーディングを指定(VS 2022 v17.13以降)
- Tools(ツール)> Options(オプション) を開く
- Environment(環境)> Documents(ドキュメント) を開く
- Save files with a specific encoding(特定のエンコーディングで保存)をオン
- Save encoding(保存エンコーディング)で UTF-8 without signature(UTF-8 BOMなし)を選ぶ
- OKで確定
この設定を入れると、以後の保存で指定したエンコーディングに揃いやすくなります。
補足:Microsoft Learn側でも同じ項目(Environment > Documents で “Save files with a specific encoding” を有効化して “Save encoding” を選ぶ)として案内されています。
方法B:プロジェクト単位で強制する(.editorconfig を使う)
IDEの個人設定ではなく、リポジトリ/プロジェクトのルールとして固定したい場合は .editorconfig が便利です。Visual StudioはEditorConfigをサポートしており、charset = utf-8 を指定できます。
例:プロジェクト直下に .editorconfig を作成
root = true
[*.{h,hpp,cpp,cxx,cc,inl,ipp}]
charset = utf-8
charset = utf-8は通常 UTF-8(BOMなし) の意図になります。- BOMありにしたい場合は
utf-8-bomを使う、という指定も可能です。
うまく設定できたか確認する方法
既存/新規ファイルを開いた状態で、Visual Studioの「エンコーディング指定で保存(Save with Encoding)」から、意図したエンコーディングになっているか確認できます(UTF-8 without signature など)。
