0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

「Unicode 文字セットを使用する」にした時の std::string → wchar_t へ可変長のまま変換 (逆変換も有り)

Last updated at Posted at 2021-06-01

概要

DXライブラリやWin32APIを使う時等Visual Studioで開発するときの「error C2664」の「'int DxLib::LoadGraph(const TCHAR *,int)': 引数 1 を 'char [128]' から 'const TCHAR *' へ変換できません。」とか「'const char *' から 'const TCHAR *' へ変換できません。」とか「'const _Elem *' から 'const TCHAR *' へ変換できません。」の回避策である「マルチ バイト文字セットを使用する」を選びたくない、使いたくない人(「Unicode 文字セットを使用する」のまま使いたい人)へのTIPS。
細かく色んなパターンでの回答はここにあるものの、課題あり(後述)。

方法: さまざまな文字列型間で変換する - Microsoft Docs
https://docs.microsoft.com/ja-jp/cpp/text/how-to-convert-between-various-string-types?view=msvc-160

今回困ったのが、従来型文字列を受け取る関数にファイルパスを変数で投げる時に wchar_t* で与えろと言われエラーとなったので、それの対処。
リンク先のサンプルでは、変換途中で new しているし、そのまま関数化しても固定長になって使いにくいのが気に入らないので、__可変長のまま投げられる__関数を考えました。

ちなみに、変数経由しなければ、文字列リテラルにLを接頭すればいけます。
(少し工夫すれば、char str[] とかにも応用出来そうな気がしますが、自分が困ったのは std::string だけだったのでご容赦を。)

戻り値バージョン

arg_ver.cpp
# include <string>
# include <vector>
# include <Windows.h>

std::vector<wchar_t> string_to_wchar(std::string in_str)
{
	setlocale(LC_ALL, "Japanese_Japan.932");
	std::vector<wchar_t> out_wstr;
	const size_t newsizew = strlen(in_str.c_str()) + 1;
	size_t convertedChars = 0;
	out_wstr.resize(newsizew);
	mbstowcs_s(&convertedChars, out_wstr.data(), newsizew, in_str.c_str(), _TRUNCATE);
	return out_wstr;
}

// 1024文字まで対応
std::string wchar_to_string(const wchar_t *in_wstr)
{
	size_t convertedChars = 0;
	char str_c[1024];
	wcstombs_s(&convertedChars, str_c, sizeof(str_c), in_wstr, _TRUNCATE);
	std::string out_str = str_c;
	return out_str;
}

int main(void) {
	// sample 1
	wchar_func(L"aaa"); // 文字列リテラルなら L を付ければよい

	// sample 2
	std::string str = "aaa";
	std::vector<wchar_t> wstr;
	wstr = string_to_wchar(str);

	wchar_func(&wstr[0]); // vectorのデータ領域は連続領域であることを利用して、先頭データのアドレスを渡してやる事で、wchar_t 配列の先頭ポインタとなる。
	wchar_func(wstr.data()); // data() も先頭ポインタなのでこちらの方がスマートか

	// sample 3
	std::string str2;
	str2 = wchar_to_string(wstr.data());
	str2 = wchar_to_string(L"aaa");

	return 0;
}

引数バージョン

arg_ver.cpp
# include <string>
# include <vector>
# include <Windows.h>

void string_to_wchar(std::string in_str, std::vector<wchar_t> &out_wstr)
{
	setlocale(LC_ALL, "Japanese_Japan.932");
	const size_t newsizew = strlen(in_str.c_str()) + 1;
	size_t convertedChars = 0;
	out_wstr.resize(newsizew);
	mbstowcs_s(&convertedChars, out_wstr.data(), newsizew, in_str.c_str(), _TRUNCATE);
}

// 1024文字まで対応
void wchar_to_string(const wchar_t *in_wstr, std::string &out_str)
{
	size_t convertedChars = 0;
	char str_c[1024];
	wcstombs_s(&convertedChars, str_c, sizeof(str_c), in_wstr, _TRUNCATE);
	out_str = str_c;
}

int main(void) {
	// sample 1
	wchar_func(L"aaa"); // 文字列リテラルなら L を付ければよい

	// sample 2
	std::string str = "aaa";
	std::vector<wchar_t> wstr;
	string_to_wchar(str, wstr);

	wchar_func(&wstr[0]); // vectorのデータ領域は連続領域であることを利用して、先頭データのアドレスを渡してやる事で、wchar_t 配列の先頭ポインタとなる。
	wchar_func(wstr.data()); // data() も先頭ポインタなのでこちらの方がスマートか

	// sample 3
	std::string str2;
	wchar_to_string(wstr.data(), str2);
	wchar_to_string(L"aaa", str2);

	return 0;
}

なお、実際に日本語が使えるかどうかは未確認なのであしからず。各自確認願います。
とりあえず英数字ではちゃんと動きました。


2021/6/4 追記
std:vector は、参照返しはNGだが、(内部的に new したりの挙動していたとしてもうまいこと出来ているので)値返しは問題ないとの記事がありましたので、戻り値バージョンも追記しました。


2021/6/12 追記
結局、日本語対応必要になって、ここ参考にさせて頂きました。

charからwchar_tへの変換 mbstowcs_s - shikaku's blog
https://blog.systemjp.net/entry/20120404/p2


2021/11/11 追記
逆変換も追記しました。
ただし、1024文字まで。変えたい方は、コード内の1024の所を変えてください。

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?