0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Visual Studio C++20 日本語対応 (UTF-8導入) メモ

Last updated at Posted at 2024-12-17

目標

本記事では Windows 用 Visual Studio における C++ プロジェクト開発において、
文字コードをデフォルトの CP932 (Shift-JIS 派生) から UTF-8 に変更するための手順をまとめる。
※文字数のカウントや文字列の分割など、文字列データの中身を参照する操作については記載していない。

C++20 で追加された char8_t を利用した、 UTF-8 固定のシステムの構築を目指す。

C++ 開発で文字コードが問題になるのは、大きく以下に分類される。

  • ソースファイル自身の文字コード
  • プログラムの入出力
  • プログラム内の静的データ (文字列リテラル)

想定環境

  • 検証時期: 2024 年 12 月
  • Windows 11
  • Visual Studio 2022 v17.12
  • MSVC C++20 (執筆時点のバージョン)

特に C++20 で追加・変更された char8_t 型を使用する。

ソースファイル

C++ プロジェクトのプロパティに /utf-8 オプションを追加

デフォルト(CP932)では UTF-8 BOM無しソースファイルを使用すると、C4819 警告が発生する。

warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいま す。データの損失を 防ぐために、ファイルを Unicode 形式で保存してください。

/utf-8 オプションを追加することで、BOM無しの UTF-8 ソースファイルが正しく扱われるようになる。

  1. プロジェクトのプロパティ を開く
  2. 構成とプラットフォームを適宜選択
  3. 構成プロパティ > C/C++ > コマンドライン > 追加のオプション に次を追加:
    /utf-8
    

https://learn.microsoft.com/ja-jp/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170

※厳密には /utf-8 オプションではなく /source-charset:utf-8 オプションのみを指定すれば十分。

(補足) その他の関連プロパティ

.editorconfigcharset を指定

.editorconfigcharset を指定すると、VisualStudio上で新規作成されるソースファイルの文字コードが指定されたものになる。

  1. Visual Studio ソリューションフォルダのルートに .editorconfig ファイルを作成し、以下を記述する。
.editorconfig
root = true
[*.{c,cc,cpp,cxx,h,hh,hpp,hxx}]
charset = utf-8

EditorConfig で一貫性のあるコーディング スタイルを定義する
EditorConfig ドキュメント

プログラム入出力、静的データ

char の代わりに char8_t , std::string の代わりに std::u8string を使用する

char, std::string は文字コードについて何も保証しないため、代わりに char8_t, std::u8string を使用することで、UTF-8 文字列を扱うことをコード上で明確にする。
※前提として、プログラム間でやり取りされる文字列データに文字コードの区別はなく、単なるバイト列として扱われる。そのため、 std::u8string が UTF-8 文字列データとして有効であるかは別の問題。

UTF-8エンコーディングされた文字の型として char8_t を追加 [P0482R6]

文字リテラルのプレフィックスを u8 にする

C++ コード内で文字リテラルを使用する場合は、 u8 プレフィックスを付けることで UTF-8 文字コードにエンコードされる。

UTF-8文字列リテラル [N2442]

Windows API で UTF-8 を扱う

例えば fopen に対する _wfopen など、Windows API ではワイド文字列 (Windows では UTF-16 を指す) を想定したC標準ライブラリ互換関数が用意されている。
こうしたワイド文字版API を呼び出す際には、UTF-8 文字列を UTF-16 に変換する必要がある。
※UTF-8 を直接渡す方法もある。: Use UTF-8 code pages in Windows apps

ここでは Windows API の MultiByteToWideChar を使用した例を示すが、
utfcpp などのライブラリを使用した方が良い場面が多い。

utf8_to_utf16.cpp
#include <string>
#include <windows.h>

// UTF-8 バイナリ (終端文字あり) を UTF-16 に変換する一例
// Windows API に渡すため u16string ではなく wstring を返す

std::wstring to_wstr(const std::u8string& u8str) {
  if (u8str.empty()) {
    return std::wstring();
  }
  // calculate the size of the destination buffer
  int wstr_size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<const char*>(u8str.c_str()), static_cast<int>(u8str.size()), nullptr, 0);
  // if the input is invalid, MultiByteToWideChar returns 0
  if (wstr_size == 0) {
    throw std::runtime_error("Invalid UTF-8 sequence");
  }
  std::wstring wstr(wstr_size, L'\0');
  // convert UTF-8 to UTF-16
  int result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, reinterpret_cast<const char*>(u8str.c_str()), static_cast<int>(u8str.size()), wstr.data(), static_cast<int>(wstr.size()));
  // if the input is invalid, MultiByteToWideChar returns 0
  if (result == 0) {
    throw std::runtime_error("Invalid UTF-8 sequence");
  }
  return wstr;
}

MultiByteToWideChar 関数 (stringapiset.h)
Windows API の Unicode

ANSI版 Windows API で UTF-8 を扱う

fopen など C標準ライブラリ互換の関数は、内部でANSI版 Windows API を使用している。
プログラム自体のコードページを変更することで、ANSI版 Windows API に UTF-8 文字列を渡すことができる。

T.B.D.

fopen, _wfopen
Use UTF-8 code pages in Windows apps
Windows/VC++ で char を UTF8 で扱う

ファイルパスは std::filesystem::path を使用する。

ファイルパスに関しては std::filesystem::path で、文字コードに依存せず文字列を扱うことができる。
path::native, path::u8string などのメンバ関数で、文字コードを変換することも可能。

コンソールのコードページを UTF-8 に変更する

プログラムをコンソールから呼び出す場合は、そのコンソール側のコードページ(使用する文字コード)を UTF-8 に変更する必要がある。
※コンソールを共有する他プロセスに影響を与える可能性があるため、注意が必要。

#include <windows.h>

int main() {
    UINT in_codepage = GetConsoleCP();
    UINT out_codepage = GetConsoleOutputCP();

    // set codepage to UTF-8
    SetConsoleCP(CP_UTF8);
    SetConsoleOutputCP(CP_UTF8);

    // do something

    // restore original codepage
    SetConsoleCP(in_codepage);
    SetConsoleOutputCP(out_codepage);
    return 0;
}

コンソールのコード ページ

関連記事

この記事の内容は、以下の関連記事と一部内容が重複する。

参考文献

その他未整理

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?