コマンド引数char* argv[2]が漢字でTCHARにできないのです

[戻る]
なおぞう 2016/03/28(月) 11:32:09
お世話になります。
VS2013 VC++で開発してます。

コマンドの第2引数にファイル出力先パスを指定しているのですが、英字なら問題ないの
ですが、たまたま日本語漢字を入れたところ、

argv[2] : C:\Log\結果  →読み込み(TCHARにすると)→ C:\\LOG\\E

というようになってしまいます。
CHARをTCHARに変換するというコードに何か問題があるのでしょうか。
どうしたら、日本語漢字をちゃんと認識できますか?
今現在調べているのですが、ご存知の方がいらっしゃいましたらアドバイスをお願いします。

int main(int argc, CHAR* argv[])
{
size_t    OutOfBufferSize = 0;
TCHAR zFolderPath[256];
memset(zFolderPath,'\0',sizeof(zFolderPath));

mbstowcs_s(&OutOfBufferSize, &zFolderPath[0], _MAX_FNAME, argv[2], _TRUNCATE);

}

tetrapod 2016/03/28(月) 12:00:11
TCHAR/_TCHAR を正しく書けばその手の変換は一切要らないはずなんだけど。
おっと wchar_t を使う際には setlocale が必要なんだった。
だから

int _tmain(int argc, _TCHAR* argv[]) {
    _tsetlocale(LC_ALL, _T(""));
    _tprintf(_T("argv[2]:<%s>\n"), argv[2]);
}

悪い事言わないから、もうちょっと _TCHAR について正しく理解しておくれ。
TCHAR と char と wchar_t は「原則」混在させないことだ。
既存のコードも全部見直すべし。

仲澤@失業者 2016/03/28(月) 12:45:29
コンソールアプリケーションだと仮定します。

まず、プロジェクトの新規作成を行って、
ウィザードにソースを生成させてみてください。
そうすると次のようなエントリーポイントが生成されます。

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

これが近代的VCにおけるメイン関数です。
_taminは#defineされていて、コンパイル時の「文字セット」の選択により

1.MBCS(=ASCII)の場合は main(int, char*[]) に置き換えられます。
2.Unicodeの場合は wmain(int, wchar_t*[]) に置き換えられます。

同じく _TCHAR(ないしTCHAR)は

3.MBCS(=ASCII)の場合は char に置き換えられます。
4.Unicodeの場合は wchar_t に置き換えられます。

さて、以上から当該のプロジェクトで起こっていることを想像すると、
たぶんコンパイル時の「文字セット」の選択がUnicodeになっていると思われます。
正しくは(または文字コードに依存したくなければ)、先の様な
定義のエントリーポイントを使用するように変更してみてはどうでしょう。

さて余禄になりますが、VS2015だと、一回転してmain()に戻っているという笑える
話も聞いてます(自分は持っていないので確かめてませんけど)。

なおぞう 2016/03/28(月) 12:48:05
>tetrapodさま
いつもありがとうございます。
受け取った時から混在しまくりでTCHARに統一するのをあきらめてしまいました。

教えていただいたコードを入れて実行してみると、

argv[2]:<??杯?見E???????>
となりました。

_tsetlocale(LC_ALL, _T("Japanese"));
これもやってみたのですが同様の結果となってしまいました。

なおぞう 2016/03/28(月) 13:18:38
>仲澤@失業者さま

ご返答ありがとうございます。
はい、文字セットはUnicodeです。

int _tmain(int argc, _TCHAR* argv[])

にしたこともあるのですが、大量のchar型を使っているエラーが出て修正を断念しました。
今、ちょっと_TCHAR*にしたのですが、55個のエラーでした。直せなくはなさそうな数で
すけど、できたら現状の問題をなんとかクリアして目をつむりたいです。

tetrapod 2016/03/28(月) 13:30:57
先ほどのコードがバグって居ないことは当方では確認済みなのだが
なおぞう氏のほうでも単体チェックしてみた?
Visual Studio のプロジェクト設定画面→デバッグ→コマンド引数を変更
全般→文字セットで Unicode / MBCS を変更してみて実行

それって渡してくるほうが悪い(=受け取り側とエンコーディングが違う)んでない?
日本語 Windows 実行環境にて標準的ファイルエンコーディングはあくまで CP932 
エンコーディング UTF-8 は標準とは言いがたいわけだが
元プログラムが UTF-8 な文字列を渡してきていたりしないか?
受け取るほうは渡された UTF-8 を CP932 と解釈しようとして失敗しているとか。
渡されたバイト列を16進表示してみるといい。

// どんなフォーマットなのかわからないので事前に長さを知ることができないから
// 表示するバイト数は固定で 16 (文字列の領域外に行くことを容認)
unsigned char* p=reinterpret_cast<unsigned char*>(argv[2]);
for (int i=0; i<16; ++i) {
    _tprintf(_T("%02X "), p[i]);
}
_tprintf(_T("\n"));

c:\結果 という文字列がプログラム間で正しく渡されたならば
MBCS 設定でビルドすると 63 3A 5C 8C 8B 89 CA 00 (以下はごみ)
Unicode 設定でビルドすると 63 00 3A 00 5C 00 50 7D 9C 67 00 00 (以下はごみ)

tetrapod 2016/03/28(月) 13:48:27
ってええ? 本当に Unicode 設定で int main(int argc, char* argv[]) としてるの?
それは間違ったプログラムであって、単純にバグっているわけだけど。

Unicode 設定 + main (char) の組み合わせは
Visual C++ 6.0 は確かリンクエラー
Visual Studio 2005 等は「リンクできて MBCS 文字列が argv に渡される」
Visual Studio 2013 は未チェック
Visual Studio 2015 は未チェック
と動作する。

そういう設定だと
argv[1] argv[2] の中身は MBCS 文字列。
_tprintf の %s は Unicode 文字列を表示しようとする
実引数で渡される文字列 (MBCS) と _tprintf の内部動作 (UTF-16) が矛盾し文字化け。

オイラの先ほどの例を <%S> にして正しく動くのであればそういうこと。

どう直すかは・・・どうしたいか次第っすね。
プログラム全体の char wchar_t TCHAR 混在を直すのが正しい態度だと思う。

なおぞう 2016/03/28(月) 14:09:09
>tetrapodさま

ご返答ありがとうございます。
とりあえず、
int _tmain(int argc, _TCHAR* argv[])

にして、直していきます。

また何かあったらアドバイス戴けますようお願い致します。

なおぞう 2016/03/28(月) 15:10:47
[[解決]]
閉じます。

古いスレッドには追加発言できません。