質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

5691閲覧

コマンドライン引数

BeatStar

総合スコア4958

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/05/09 03:47

趣味で C/C++ ( Windows API 実装 ) でやっています。

コマンドライン引数を取得して処理することに関してです。

「C言語 入門」, 「C++ 入門」で検索すると

"コマンドライン引数" の項目 があったりします。

これに関しては問題ないのですが、CUI, GUIどちらでも使えるようにしたいので、

クラス化 ( or 関数化 ) したいと思っています。

CUIの場合は、 main関数の int argc, char **argv で比較的簡単に取得できます。

GUI ( Windows API でやる場合 ) の場合は PTSTR でしたっけ?

それに入っているようですが、

$main abc -a -b -f file1.txt

と打つと、

"main abc -a -b -f file1.txt" で一つとなるので、

これを編集するのが大変です。

なので Google 「C言語 Windows API コマンドライン引数」みたいに検索したところ、

「山内の授業補完のページ/Windowsアプリ/argcとargv - 東邦大学理学部情報科学科 山内のサイト」

がヒットしました。

こちらのサイトのソースコードを拝借してクラス化して... とやってみました。

一応うまくいったのですが、ある条件のときがおかしくなります。

"ある条件"というのは よくわかっていませんが、場合によっては何故かコマンドライン引数が 途中で切れるというか、文字化けするというか、
なんかわけわからないことになります。

そのときのデータを比較してみると 「日本語が含まれている」 といった感じです。

(実行ファイルの)ファイルパス とか コマンドライン引数として 日本語で 渡すとか。

例:
$main -f "C:\やっほー\file1.txt" -d "このデータが追加されればOK"

rem これを cout とか MessageBoxとかで見ると
rem main -f "C:\やっほー\・" -d "・。:・・"
rem みたいになっている。

rem ※ 結果は例です。

ソースコード:
(字数制限のため、他のサイトを利用しています。)
https://pastebin.com/J5Sy7ECh

呼び出し側は

C++

1 2CCommandLine* CmdLine = new CCommandLine(); 3 4for( int i = 0; i < CmdLine->Size(); i++ ){ 5 // CmdLine->At( i ) を表示 6} 7 8delete CmdLine;

のようにしています。

ですが、なぜか文字化けというか、途中で途切れるというか...

うまくいきません。

階層を変更して、 Cドライブ直下とかのように 日本語が入らないようにすると普通に ( ファイルパスの方は ) うまくいきます。

これってどういう理由なのでしょうか?

一応、コード上では wstring -> string と変更する関数があります。

char型配列と wchar_t型配列 で入れたときの大きさ ( 要素数 ) が違うので、

w -> s にするときには 2倍にしてみました。

ですが、それでも同じ...

GUI の場合は (実行ファイルとコマンドライン引数が) 一つになっているので
自分で分解する関数を作るのもいいですが、
やり方がわかりません。
strtok関数等で分解する分にはいいですが、区切り方が...

基本的に 半角スペースで区切られているので

区切り文字 = 半角スペース

とみなすこともできますが、

"abc test"

という風に 半角スペースが "文字" として出現している場合もあります。

他の文字を当てる... これも方法としてはアリですが、
ユーザからすると「わからない」ので、ボツ。

上記コードを w -> c に変換せずに使う方法もありますが、
これだとちょっと厳しい...

CUIだと使えないことが多い ( ほとんどの関数は char型配列を想定している ) ので、NG。
しかも GUIだとしても C/C++本来の関数やクラスを使う場合も同様。

なので どうしても w -> c としないといけません。

どういう風に考えれば宜しいのでしょうか...

ご存じの方、解決法( へのヒント ) を宜しくお願い致します。

[情報]
言語 : C/C++
WinAPI : あり
コンパイラ: MinGW ( g++ )

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t_obara

2017/05/09 05:50

引数で日本語を指定した場合の日本語文字コードと、MinGWのエンコーディングを確認するとかはやりました?
guest

回答3

0

こんにちは。

Visual C++で山内氏ページの最後の2つのソースを走らせてみました。(#include <shellapi.h>を補い、単純なtypo修正。)前者は文字セットとしてUnicode指定、後者はマルチバイト文字セット指定しました。
コマンド・ライン引数に、-f "C:\やっほー\file1.txt" -d "このデータが追加されればOK"を指定しましたが、文字化けや途切れは発生しませんでした。

ところで、MinGWは文字コードの扱いがVisual C++とはそこそこ異なります。特にchar型文字列リテラルは全く違います。gccはソースの文字コードに合わせて適切にコンパイル・オプションを指定する必要があります。Visual C++はソースを適切に保存していれば、自動的にShift-JISとなります。などなど結構違います。

上記相違等にハマる、もしくは、日本語文字コードの扱いが不適切なのだろうと思われます。

MinGWで_tmain()を使用する方法が参考になりそうです。
ただし、文字コードの知識も必要です。その時は、最近、文字コードの問題について書きましたのでここも参考にしてみて下さい。


【蛇足ですが】
正直なところ、マルチ・プラットフォームではないWindows APIを直接使うようなプログラムで日本語を扱う場合は、MinGWを使うよりVisual C++を使った方が現実的かも知れません。
また、趣味プログラムなら無料のCommunityを使えますし。

投稿2017/05/09 05:57

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

Windowsコマンドプロンプトの文字化けには色々悩まされたのですが、色々やってみた感じWindows APIで出来ることは全てWindows APIを使ったほうがうまくいくみたいです。

subsystem:guiの時はコマンドライン引数の取得にGetCommandLineW()CommandLineToArgvWを使う(subsystem:consoleの時に使うと挙動がおかしくなる)
入力にはReadConsole、出力にはWriteConsoleを使う。

下記のコードでは使用していませんが、
ワイド文字とマルチバイト文字の相互変換にはwcstombsではなくMultiByteToWideCharWideCharToMultiByteを使って相互変換する
printf等で書き込む時はsetlocaleでは無くGetConsoleOutputCPSetConsoleOutputCPでコードページを変更する等でしょうか。

c++

1#include <windows.h> 2 3#include <stdio.h> 4#include <tchar.h> 5 6int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 7 LPTSTR lpCmdLine, int nCmdShow) 8{ 9 AttachConsole(ATTACH_PARENT_PROCESS); 10 11 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); 12 wchar_t buffer[_MAX_PATH + 1] = {}; 13 14 int nArgs = 0; 15 LPWSTR* lplpszArgs = nullptr; 16 17 // コマンドライン文字列をargvとargcと同じ形式に分ける 18 // CommandLineToArgvWはUnicode版しか存在しない 19 lplpszArgs = CommandLineToArgvW(GetCommandLineW(), &nArgs); 20 21 for (int i = 0; i < nArgs; i++) 22 { 23 wprintf(L"argv[i] = %d\n", i, lplpszArgs[i]); 24 _snwprintf_s(buffer, sizeof(buffer), _MAX_PATH, L"argv[%d] = %s\n", i, 25 lplpszArgs[i]); 26 // コンソールバッファに文字列を挿入する 27 WriteConsoleW(hStdOut, buffer, wcslen(buffer), nullptr, nullptr); 28 } 29 30 FreeConsole(); 31 32 return 0; 33}

出力結果

Windows10でしか確認していないので、古いバージョンのWindowsだとどうなるかわかりませんが…。

subsystem:guiAttachConsole(ATTACH_PARENT_PROCESS)を使った時の不具合については下記の質問の方に調べた事をまとめました。
GUI と CUI の共存

投稿2017/05/24 07:12

編集2017/05/24 07:19
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

boostが使用できるのであれば、
Boost.ProgramOptions
が便利です。

gccとかなら確かgetopt()関数というのが有りますね。
[C/C++]プログラムにコマンドラインからUNIX風のオプションを渡す方法(getopt関数)

投稿2017/05/11 08:08

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問