Unicode対応ライブラリを作成する場合についての質問です
ある関数の中身が、
マルチバイト用の関数と、Unicode用の関数、
それぞれ別な中身を用意する必要があると知りました
たとえば、
void DebugPrintA()
{
OutputDebugStringA("");
}
void DebugPrintW()
{
OutputDebugStringW(L"");
}
という実装で、公開ヘッダは
#ifdef _UNICODE
#define DebugPrint DebugPrintW
#else
#define DebugPrint DebugPrintA
#endif
しかしこうすると、同じ関数が2つ出来るために、
メンテナンス性の低下を引き起こします
OutputDebugStringなどの文字コードに関係するコードが1行でも出てくれば、
関数を2つにする必要が出てきてしまいます
これはなんとかして簡略な方法はありませんか?
それとも考え方が間違っていますでしょうか?
Unicodeと静的リンクライブラリについて
Re:Unicodeと静的リンクライブラリについて
マルチバイト・unicode の両方に対応させるには、どうしても関数をふたつ作る必要があります。
私も同じような問題に当たったことがありますが、そのときはこんな風にしてみました。
ちょっと強引かもしれないけど…
void DebugPrintA( char* cstr )
{
// マルチバイト文字をワイド文字に変換した後、処理は DebugPrintW に丸投げ
wchar_t wbuf[ 512 ];
toWideString( wbuf, 512, str );
OutputDebugStringW( wbuf );
}
void DebugPrintW( wchar_t* wstr )
{
OutputDebugStringW( wstr );
// ...
}
これなら DebugPrintW の中身を管理するだけで大丈夫! …なはずです。^^;
私も同じような問題に当たったことがありますが、そのときはこんな風にしてみました。
ちょっと強引かもしれないけど…
void DebugPrintA( char* cstr )
{
// マルチバイト文字をワイド文字に変換した後、処理は DebugPrintW に丸投げ
wchar_t wbuf[ 512 ];
toWideString( wbuf, 512, str );
OutputDebugStringW( wbuf );
}
void DebugPrintW( wchar_t* wstr )
{
OutputDebugStringW( wstr );
// ...
}
これなら DebugPrintW の中身を管理するだけで大丈夫! …なはずです。^^;
Re:Unicodeと静的リンクライブラリについて
ひとつで済ませる方法がないわけではありません。
基本的にはりゅんさんの方法と同じで、いったんワイド文字列になおしてからワイド文字版を呼ぶことになりますが...
まず、準備として...
std::wstring to_wstring(char const* s);
std::wstring to_wstring(wchar_t const* wcs);
のようなワイド文字列に変換する関数を作っておきます。
本来は必要がない、ワイド文字列→ワイド文字列への変換関数も作るのがポイントです。
その上で、
template <typename charT>
void DebugPrint(charT const* s)
{
::OutputDebugString(to_wstring(s).c_str());
}
とすれば、ひとつの関数定義で済むようになります。
基本的にはりゅんさんの方法と同じで、いったんワイド文字列になおしてからワイド文字版を呼ぶことになりますが...
まず、準備として...
std::wstring to_wstring(char const* s);
std::wstring to_wstring(wchar_t const* wcs);
のようなワイド文字列に変換する関数を作っておきます。
本来は必要がない、ワイド文字列→ワイド文字列への変換関数も作るのがポイントです。
その上で、
template <typename charT>
void DebugPrint(charT const* s)
{
::OutputDebugString(to_wstring(s).c_str());
}
とすれば、ひとつの関数定義で済むようになります。
Re:Unicodeと静的リンクライブラリについて
ご回答ありがとうございます
ちょっと自分が勘違いしているかもしれないのですが、
ライブラリを利用する立場の話ですが、
マルチバイトの設定でビルドしているにもかかわらず、
Unicodeの関数を呼んでも問題はないのですか?
ためしに
コンソールにて、マルチバイト設定で
wprintf(L"これはワイド文字列");
としましたが、
コンパイル、リンク->正常
出力->なし
という状態で正常に動かなかったのですが
これは何がいけないのでしょうか?
ちょっと自分が勘違いしているかもしれないのですが、
ライブラリを利用する立場の話ですが、
マルチバイトの設定でビルドしているにもかかわらず、
Unicodeの関数を呼んでも問題はないのですか?
ためしに
コンソールにて、マルチバイト設定で
wprintf(L"これはワイド文字列");
としましたが、
コンパイル、リンク->正常
出力->なし
という状態で正常に動かなかったのですが
これは何がいけないのでしょうか?
Re:Unicodeと静的リンクライブラリについて
> マルチバイトの設定でビルドしているにもかかわらず、
> Unicodeの関数を呼んでも問題はないのですか?
Visual C++に限った話だとすると、問題ありません。
> コンソールにて、マルチバイト設定で
> wprintf(L"これはワイド文字列");
> としましたが、
> コンパイル、リンク->正常
> 出力->なし
> という状態で正常に動かなかったのですが
> これは何がいけないのでしょうか?
ロケールを設定していないからでは?
wprintfを使う前には、setlocaleで少なくともLC_CTYPEを設定しておかなければなりません。
> Unicodeの関数を呼んでも問題はないのですか?
Visual C++に限った話だとすると、問題ありません。
> コンソールにて、マルチバイト設定で
> wprintf(L"これはワイド文字列");
> としましたが、
> コンパイル、リンク->正常
> 出力->なし
> という状態で正常に動かなかったのですが
> これは何がいけないのでしょうか?
ロケールを設定していないからでは?
wprintfを使う前には、setlocaleで少なくともLC_CTYPEを設定しておかなければなりません。
Re:Unicodeと静的リンクライブラリについて
wprintfは別な要因でした、すみませんありがとうございます
テンプレートに関して、ああ、こんな方法もあるのか!
と思ったのですが、
ヘッダーに全部書くとなると、
見えて欲しくないものも公開ヘッダに含まれてしまう
→さらにもう一段cppに包む手間が発生する
void DebugPrintA()
{
DebugPrint<char>();
}
void DebugPrintW()
{
DebugPrint<wchar_t>();
}
という実装になるといった感じだろうと想像することができました
内部newのあるstringのオーバーヘッドも気になるところでしょうか
その代わりに、関数は1つで済む
ちょっと自分にはメリットとデメリットが交錯して判断が難しくなってきました
この手法はよく用いられる方法なのでしょうか?
>Visual C++に限った話だと、
というのも気になります
これはかなり環境依存の解決方法ということになってしまうのでしょうか?
テンプレートに関して、ああ、こんな方法もあるのか!
と思ったのですが、
ヘッダーに全部書くとなると、
見えて欲しくないものも公開ヘッダに含まれてしまう
→さらにもう一段cppに包む手間が発生する
void DebugPrintA()
{
DebugPrint<char>();
}
void DebugPrintW()
{
DebugPrint<wchar_t>();
}
という実装になるといった感じだろうと想像することができました
内部newのあるstringのオーバーヘッドも気になるところでしょうか
その代わりに、関数は1つで済む
ちょっと自分にはメリットとデメリットが交錯して判断が難しくなってきました
この手法はよく用いられる方法なのでしょうか?
>Visual C++に限った話だと、
というのも気になります
これはかなり環境依存の解決方法ということになってしまうのでしょうか?
Re:Unicodeと静的リンクライブラリについて
> void DebugPrintA()
> {
> DebugPrint<char>();
> }
> void DebugPrintW()
> {
> DebugPrint<wchar_t>();
> }
> という実装になるといった感じだろうと想像することができました
最終的に関数名を分けるのであれば...
#ifdef _UNICODE
#define AorW(x) x##W
#else
#define AorW(x) x##A
#endif
のようなマクロを作っておいて、
void AorW(DebugPrint)(LPCTSTR s)
{
OutputDebugString(s);
}
と、関数定義を一度だけ定義しておき、2回コンパイルを通せばよいのです。
IDEでもできないことはありませんが、Makefileを書いた方が簡単かもしれません。
> 内部newのあるstringのオーバーヘッドも気になるところでしょうか
それほどタイムクリティカルな処理なのであれば、もっといろいろなことに配慮しなければならなくなります。
> この手法はよく用いられる方法なのでしょうか?
ジェネリックプログラミングでは、本来違うものを同じように書けるように工夫するのは普通だと思います。
> これはかなり環境依存の解決方法ということになってしまうのでしょうか?
Windows APIを使う時点で完全に環境依存だと思いますが...
> {
> DebugPrint<char>();
> }
> void DebugPrintW()
> {
> DebugPrint<wchar_t>();
> }
> という実装になるといった感じだろうと想像することができました
最終的に関数名を分けるのであれば...
#ifdef _UNICODE
#define AorW(x) x##W
#else
#define AorW(x) x##A
#endif
のようなマクロを作っておいて、
void AorW(DebugPrint)(LPCTSTR s)
{
OutputDebugString(s);
}
と、関数定義を一度だけ定義しておき、2回コンパイルを通せばよいのです。
IDEでもできないことはありませんが、Makefileを書いた方が簡単かもしれません。
> 内部newのあるstringのオーバーヘッドも気になるところでしょうか
それほどタイムクリティカルな処理なのであれば、もっといろいろなことに配慮しなければならなくなります。
> この手法はよく用いられる方法なのでしょうか?
ジェネリックプログラミングでは、本来違うものを同じように書けるように工夫するのは普通だと思います。
> これはかなり環境依存の解決方法ということになってしまうのでしょうか?
Windows APIを使う時点で完全に環境依存だと思いますが...
Re:Unicodeと静的リンクライブラリについて
どうせウィンドウズ依存だからVCにもガンガン依存しちゃえ!
というのもひとつの考え方ですが、
せめてVCのみの機能は控える、というのも勉強のためには良いかなと
考えたからです
このあたりは自分で実際に今後試しながらやっていきます
タイムクリティカルというよりは、
ライブラリを使う側でマルチバイトだけで組む場合、
本来は必要なかったUnicode変換の処理が毎回入ってしまう
同じくUnicode→Unicodeでもコピーが発生する
というのに対してもったいなさといいますか、そういった印象があがってしまいました
OSがUnicodeベースであれば、
マルチバイトであっても内部で変換が入るらしいので、
このオーバーヘッドはたいしたことない、と考えることもできそうですが
まだ実際に計測したわけではないです
関数定義を一度だけ定義しておき、2回コンパイル
というのは、.Libファイルごと分けてしまうということでしょうか?
それとも、
Makefile(私は詳しくないです)
の設定で.objを2つ作ってあくまでも1つの.libという形でしょうか?
というのもひとつの考え方ですが、
せめてVCのみの機能は控える、というのも勉強のためには良いかなと
考えたからです
このあたりは自分で実際に今後試しながらやっていきます
タイムクリティカルというよりは、
ライブラリを使う側でマルチバイトだけで組む場合、
本来は必要なかったUnicode変換の処理が毎回入ってしまう
同じくUnicode→Unicodeでもコピーが発生する
というのに対してもったいなさといいますか、そういった印象があがってしまいました
OSがUnicodeベースであれば、
マルチバイトであっても内部で変換が入るらしいので、
このオーバーヘッドはたいしたことない、と考えることもできそうですが
まだ実際に計測したわけではないです
関数定義を一度だけ定義しておき、2回コンパイル
というのは、.Libファイルごと分けてしまうということでしょうか?
それとも、
Makefile(私は詳しくないです)
の設定で.objを2つ作ってあくまでも1つの.libという形でしょうか?
Re:Unicodeと静的リンクライブラリについて
> せめてVCのみの機能は控える、というのも勉強のためには良いかなと
> 考えたからです
それはちょっと厳しいのでは?
元の質問は、
> マルチバイトの設定でビルドしているにもかかわらず、
> Unicodeの関数を呼んでも問題はないのですか?
なので、それであればライブラリの作りなどに完全に依存していますから。
> ライブラリを使う側でマルチバイトだけで組む場合、
> 本来は必要なかったUnicode変換の処理が毎回入ってしまう
これについてはご自身で書かれているように、どこで変換するかだけの話です。
もっとも、Visual C++に依存したくないのであれば、MutibyteToWideCharなどは使えませんので、std::codecvtファセットを使うなどしなければならなくなります。これだとオーバーヘッドはもう少し増えるでしょうね。
> 同じくUnicode→Unicodeでもコピーが発生する
> というのに対してもったいなさといいますか、そういった印象があがってしまいました
本質ではないところでもう一手間かかりますので、分かりにくいかと思って省略しましたが、その問題は回避可能です。
> 関数定義を一度だけ定義しておき、2回コンパイル
> というのは、.Libファイルごと分けてしまうということでしょうか?
> それとも、
> Makefile(私は詳しくないです)
> の設定で.objを2つ作ってあくまでも1つの.libという形でしょうか?
Makefileであれば、
DebugPrintA.obj: DebugPrint.cpp
cl /c DebugPrint.cpp
DebugPrintW.obj: DebugPrint.cpp
cl /c /D_UNICODE DebugPrint.cpp
のように、ひとつのソースファイルから複数のオブジェクトファイルを生成できるということです。

> 考えたからです
それはちょっと厳しいのでは?
元の質問は、
> マルチバイトの設定でビルドしているにもかかわらず、
> Unicodeの関数を呼んでも問題はないのですか?
なので、それであればライブラリの作りなどに完全に依存していますから。
> ライブラリを使う側でマルチバイトだけで組む場合、
> 本来は必要なかったUnicode変換の処理が毎回入ってしまう
これについてはご自身で書かれているように、どこで変換するかだけの話です。
もっとも、Visual C++に依存したくないのであれば、MutibyteToWideCharなどは使えませんので、std::codecvtファセットを使うなどしなければならなくなります。これだとオーバーヘッドはもう少し増えるでしょうね。
> 同じくUnicode→Unicodeでもコピーが発生する
> というのに対してもったいなさといいますか、そういった印象があがってしまいました
本質ではないところでもう一手間かかりますので、分かりにくいかと思って省略しましたが、その問題は回避可能です。
> 関数定義を一度だけ定義しておき、2回コンパイル
> というのは、.Libファイルごと分けてしまうということでしょうか?
> それとも、
> Makefile(私は詳しくないです)
> の設定で.objを2つ作ってあくまでも1つの.libという形でしょうか?
Makefileであれば、
DebugPrintA.obj: DebugPrint.cpp
cl /c DebugPrint.cpp
DebugPrintW.obj: DebugPrint.cpp
cl /c /D_UNICODE DebugPrint.cpp
のように、ひとつのソースファイルから複数のオブジェクトファイルを生成できるということです。

Re:Unicodeと静的リンクライブラリについて
たくさんの詳しいご回答ありがとうございました
かなり知識を深めることが出来ました!
またMakefile、template
のことについて等非常に参考になりました
得た知識を元に
もう一度自分のソースと相談し、進めていきたいと思います。
かなり知識を深めることが出来ました!
またMakefile、template
のことについて等非常に参考になりました
得た知識を元に
もう一度自分のソースと相談し、進めていきたいと思います。