ソースコードのエンコーデングは多言語化対応のためにUTF8が主流であるがUTF8だと単純にprintf(“日本語”)すると化けてしまう。
日本ではコンソールのコードページがCP932であるから化けるのは当たり前ではあるのだがUTF8からCP932にいちいち変換するのは煩わしいし、-fexec-charset=CP932を使う方法はCP932専用アプリになってしまうのでお勧めでもない。
最良な方法はソースコードのエンコーデングに合わせてコンソールのコードページもUTF8にすることであるが次のように手動で切り替えするのも煩わしかったりする。
chcp 65001
そこでコンソールのコードページをUTF8に変更したりコードページ文字列/UTF8文字列/ワイド文字列の三つ巴の双方向変換が行えるライブラリを作ってみた。
変換バッファ領域は自動管理なので簡単に使えるし、おまけにマルチスレッド対応も...って、余計なお世話かな?(-_-;)
ちなみにコンソールのコードページを変更しても起動時のコードページはそのままなのでコマンドライン引数のエンコーディングには気を付ける必要がある。
コンソールのコードページを変更した場合はfromCP(argv[x])或いはtoXXX(fromCP(argv[x]))のようにコマンドライン引数のエンコーディングを変換してから処理しなければならない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <stdio.h> #include "widechar.h" void test() { WideChar wc; const char *utf8 = "日本語"; // UTF8文字列 const wchar_t *wstr = L"日本語"; // ワイド文字列 printf("%s\n", utf8); printf("%s\n", wc.toCON(wstr)); } int main(int argc, char **argv) { WideChar wc(true); // コンソールのコードページをUTF8に変更。 test(); return 0; } |
変換バッファ領域の開放はスコープを抜けた時点で行われるためループ内で変換関数を使うときはループ内でのWideChar宣言を推奨。ループ外で宣言するとループ毎にメモリ消費量が増加するので注意してほしい。
【メモリ消費量が多い】
1 2 3 4 5 6 7 8 |
void bad(void) { WideChar wc; // ループの外で宣言 for (...) { wc.toXXX(...); } } |
【メモリ消費量が少ない】
1 2 3 4 5 6 7 8 |
void good(void) { for (...) { WideChar wc; // ループの中で宣言 wc.toXXX(...); } } |
【概要】
1 |
WideChar(bool chcp = false, UINT codepage = CP_UTF8) |
引数にtrueを指定したときコンソールの入出力コードページを変更(規定値はUTF8)しスコープを抜けたときに元に戻す。
1 |
const char *toACPfromUTF8(const char *str) |
UTF8文字列をANSI文字列へ変換する。
1 |
const char *toOEMCPfromUTF8(const char *str) |
UTF8文字列をOEM文字列へ変換する。
1 |
const char *toCONfromUTF8(const char *str) |
UTF8文字列を現在のコンソールのコードページ文字列へ変換する。
1 |
const char *toCPfromUTF8(const char *str) |
UTF8文字列を起動時のコンソールのコードページ文字列へ変換する。
1 |
const char *toCPfromUTF8(const char *str, UINT codepage) |
UTF8文字列を指定のコードページ文字列へ変換する。
1 |
const char *toUTF8fromACP(const char *str) |
ANSI文字列をUTF8文字列へ変換する。
1 |
const char *toUTF8fromOEMCP(const char *str) |
OEM文字列をUTF8文字列へ変換する。
1 |
const char *toUTF8fromCON(const char *str) |
現在のコンソールのコードページ文字列をUTF8文字列へ変換する。
1 |
const char *toUTF8fromCP(const char *str) |
起動時のコンソールのコードページ文字列をUTF8文字列へ変換する。
1 |
const char *toUTF8fromCP(const char *str, UINT codepage) |
指定のコードページ文字列をUTF8文字列へ変換する。
1 |
const char *toACP(const wchar_t *wstr) |
ワイド文字列をANSI文字列へ変換する。
1 |
const char *toOEMCP(const wchar_t *wstr) |
ワイド文字列をOEM文字列へ変換する。
1 |
const char *toUTF8(const wchar_t *wstr) |
ワイド文字列をUTF8文字列へ変換する。
1 |
const char *toCON(const wchar_t *wstr) |
ワイド文字列を現在のコンソールのコードページ文字列へ変換する。
1 |
const char *toCP(const wchar_t *wstr) |
ワイド文字列を起動時のコンソールのコードページ文字列へ変換する。
1 |
const char *toCP(const wchar_t *wstr, UINT codepage) |
ワイド文字列を指定のコードページ文字列へ変換する。
1 |
const wchar_t *fromACP(const char *str) |
ANSI文字列をワイド文字列へ変換する。
1 |
const wchar_t *fromOEMCP(const char *str) |
OEM文字列をワイド文字列へ変換する。
1 |
const wchar_t *fromUTF8(const char *str) |
UTF8文字列をワイド文字列へ変換する。
1 |
const wchar_t *fromCON(const char *str) |
現在のコンソールのコードページ文字列をワイド文字列へ変換する。
1 |
const wchar_t *fromCP(const char *str) |
起動時のコンソールのコードページ文字列をワイド文字列へ変換する。
1 |
const wchar_t *fromCP(const char *str, UINT codepage) |
指定のコードページ文字列をワイド文字列へ変換する。
【修正】
2024-01-20
コンソールのコードページをUTF8固定ではなく指定できるように変更。
2024-01-18
変換メソッドを追加。
【ライブラリ】
GUIにはA/WサフィックスのAPIがある。AサフィックスのAPIにはOEMCP文字列、WサフィックスのAPIにはワイド文字列を使うこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
/* widechar.h - WideChar Support Library Copyright (c) 2024 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #pragma once #include <windows.h> #include <malloc.h> #include <string> #include <vector> class WideChar { public: WideChar(bool chcp = false, UINT codepage = CP_UTF8) : _in_cp(CP_OEMCP), _out_cp(CP_OEMCP) { InitializeCriticalSection(&_criticalsection); if (_cmdline == CP_OEMCP) _console = _cmdline = GetConsoleCP(); if (chcp) begin(codepage); } virtual ~WideChar(void) { end(); DeleteCriticalSection(&_criticalsection); } const char *toACPfromUTF8(const char *str) { return toACP(fromUTF8(str)); } const char *toOEMCPfromUTF8(const char *str) { return toOEMCP(fromUTF8(str)); } const char *toCONfromUTF8(const char *str) { return toCON(fromUTF8(str)); } const char *toCPfromUTF8(const char *str) { return toCP(fromUTF8(str)); } const char *toCPfromUTF8(const char *str, UINT codepage) { return toCP(fromUTF8(str), codepage); } const char *toUTF8fromACP(const char *str) { return toUTF8(fromACP(str)); } const char *toUTF8fromOEMCP(const char *str) { return toUTF8(fromOEMCP(str)); } const char *toUTF8fromCON(const char *str) { return toUTF8(fromCON(str)); } const char *toUTF8fromCP(const char *str) { return toUTF8(fromCP(str)); } const char *toUTF8fromCP(const char *str, UINT codepage) { return toUTF8(fromCP(str, codepage)); } const char *toACP(const wchar_t *wstr) { return toCP(wstr, CP_ACP); } const char *toOEMCP(const wchar_t *wstr) { return toCP(wstr, CP_OEMCP); } const char *toUTF8(const wchar_t *wstr) { return toCP(wstr, CP_UTF8); } const char *toCON(const wchar_t *wstr) { return toCP(wstr, _console); } const char *toCP(const wchar_t *wstr) { return toCP(wstr, _cmdline); } const char *toCP(const wchar_t *wstr, UINT codepage) { int len = WideCharToMultiByte(codepage, 0, wstr, -1, NULL, 0, NULL, NULL); #if defined(__GNUC__) char buf[len > 0 ? len : 1]; #else char *buf = (char *)_alloca((len > 0 ? len : 1) * sizeof(*buf)); #endif buf[0] = 0; WideCharToMultiByte(codepage, 0, wstr, -1, buf, len, NULL, NULL); EnterCriticalSection(&_criticalsection); size_t last = _strings.size(); _strings.push_back(buf); LeaveCriticalSection(&_criticalsection); return _strings[last].c_str(); } const wchar_t *fromACP(const char *str) { return fromCP(str, CP_ACP); } const wchar_t *fromOEMCP(const char *str) { return fromCP(str, CP_OEMCP); } const wchar_t *fromUTF8(const char *str) { return fromCP(str, CP_UTF8); } const wchar_t *fromCON(const char *str) { return fromCP(str, _console); } const wchar_t *fromCP(const char *str) { return fromCP(str, _cmdline); } const wchar_t *fromCP(const char *str, UINT codepage) { int len = MultiByteToWideChar(codepage, 0, str, -1, NULL, 0); #if defined(__GNUC__) wchar_t buf[len > 0 ? len : 1]; #else wchar_t *buf = (wchar_t *)_alloca((len > 0 ? len : 1) * sizeof(*buf)); #endif buf[0] = 0; MultiByteToWideChar(codepage, 0, str, -1, buf, len); EnterCriticalSection(&_criticalsection); size_t last = _wstrings.size(); _wstrings.push_back(buf); LeaveCriticalSection(&_criticalsection); return _wstrings[last].c_str(); } void begin(UINT codepage) { _console = codepage; if (_in_cp == CP_OEMCP) _in_cp = _cmdline; if (_out_cp == CP_OEMCP) _out_cp = GetConsoleOutputCP(); SetConsoleCP(codepage); SetConsoleOutputCP(codepage); } void end(void) { if (_in_cp != CP_OEMCP) SetConsoleCP(_in_cp); if (_out_cp != CP_OEMCP) SetConsoleOutputCP(_out_cp); _in_cp = _out_cp = CP_OEMCP; } private: static UINT _console; static UINT _cmdline; UINT _in_cp; UINT _out_cp; std::vector<std::string> _strings; std::vector<std::wstring> _wstrings; CRITICAL_SECTION _criticalsection; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/* widechar.cpp - WideChar Support Library Copyright (c) 2024 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #include "widechar.h" UINT WideChar::_console = CP_OEMCP; UINT WideChar::_cmdline = CP_OEMCP; |