C++のコマンドライン引数とは、プログラムを実行するときに、実行ファイル名の後ろへ指定する値のことです。
たとえば、プログラムにファイル名、数値、オプション、モード指定などを渡したい場合に使います。
コマンドライン引数を使うと、プログラムの中身を書き換えなくても、実行時に動作を変えられます。
ファイル変換ツール、ログ解析ツール、画像処理ツール、バッチ処理プログラムなどでは、コマンドライン引数がよく使われます。
C++でコマンドライン引数を受け取る仕組み
C++では、main 関数の引数を使ってコマンドライン引数を受け取ります。
代表的なのが、argc と argv です。
argcとは
argc は、コマンドライン引数の個数を表します。
ただし、ここでいう個数には、ユーザーが指定した引数だけでなく、通常はプログラム名も含まれます。
たとえば、プログラム名の後ろに3つの値を指定した場合、argc は4になります。
なぜなら、次のように数えられるためです。
プログラム名が1つ目として数えられ、その後にユーザーが指定した引数が続きます。
そのため、コマンドライン引数を扱うときは、「ユーザーが指定した引数の数」と「argc の値」は必ずしも同じではない点に注意が必要です。
argvとは
argv は、コマンドラインで渡された文字列を格納している配列のようなものです。
argv の中には、プログラム名やユーザーが指定した引数が順番に入ります。
一般的には、argv[0] にプログラム名、argv[1] にユーザーが指定した最初の引数、argv[2] に2つ目の引数が入ります。
つまり、ユーザーが指定した最初の引数を取り出したい場合は、argv[0] ではなく argv[1] を見る必要があります。
argv[0]に入る内容
argv[0] には、通常、プログラム名または実行時に指定されたパスが入ります。
ただし、必ずしも「実行ファイル名だけ」が入るとは限りません。
実行方法によって内容が変わる
プログラムをどのように実行したかによって、argv[0] の内容は変わることがあります。
たとえば、カレントディレクトリから実行した場合は、相対パスのような形になることがあります。
一方、フルパスで実行した場合は、フルパスが入ることもあります。
また、シンボリックリンクやショートカットのような仕組みを経由して実行した場合、実際の実行ファイル名とは異なる名前が入る可能性もあります。
argv[0]を過信しないことが大切
argv[0] は、プログラム自身の名前を表示したり、使い方を案内したりする用途では便利です。
しかし、常に正確な実行ファイル名が入るとは限らないため、ファイルの場所を厳密に判定する目的では注意が必要です。
初心者のうちは、argv[0] は「プログラム名のようなものが入る場所」と理解しておくとよいでしょう。
ユーザーが指定した最初の引数はargv[1]
コマンドライン引数を学ぶときに特に重要なのが、argv[0] と argv[1] の違いです。
argv[0] は、通常、プログラム名です。
ユーザーが実際に指定した最初の引数は argv[1] です。
初心者が間違えやすいポイント
初心者がよく間違えるのは、argv[0] を「1つ目の引数」だと思ってしまうことです。
しかし、実際には argv[0] はプログラム名として扱われることが多く、ユーザーが指定した値は argv[1] 以降に入ります。
そのため、コマンドライン引数を処理するときは、基本的に argv[1] から確認します。
引数があるかどうかを確認する必要がある
argv[1] を使う前には、必ず argc を確認する必要があります。
なぜなら、ユーザーが何も引数を指定せずにプログラムを実行した場合、argv[1] は存在しないからです。
存在しない引数を無理に参照すると、プログラムが異常終了したり、予期しない動作をしたりする可能性があります。
そのため、コマンドライン引数を扱うときは、まず必要な数の引数が渡されているかを確認するのが基本です。
コマンドライン引数は文字列として渡される
コマンドライン引数で渡された値は、基本的に文字列として扱われます。
たとえば、ユーザーが 100 という値を指定したとしても、それは最初から整数として扱われるわけではありません。
C++のプログラム内では、まず文字列として受け取ります。
数値として使うには変換が必要
コマンドライン引数で受け取った値を計算に使いたい場合は、文字列から数値へ変換する必要があります。
整数として使うなら整数への変換、小数として使うなら小数への変換を行います。
たとえば、年齢、回数、処理件数、ファイルサイズ、倍率などを引数として受け取る場合は、数値変換が必要になります。
変換エラーにも注意する
ユーザーが必ず正しい数値を入力してくれるとは限りません。
数値を期待している場所に、文字列や記号が入力されることもあります。
そのため、実用的なプログラムでは、数値変換に失敗した場合の処理も用意しておく必要があります。
たとえば、「数値を指定してください」「範囲外の値です」といったエラーメッセージを表示すると、ユーザーにとって分かりやすいプログラムになります。
std::stoiなどで数値変換するときの注意点
C++では、文字列を整数や小数に変換するための機能があります。
ただし、これらを使うときには注意点もあります。
先頭だけ数値なら変換される場合がある
文字列を数値に変換する処理では、文字列全体が完全な数値でなくても、先頭部分だけが数値として解釈される場合があります。
たとえば、先頭に数字があり、その後ろに英字が続いているような文字列では、先頭の数字部分だけが変換されることがあります。
そのため、「入力全体が正しい数値かどうか」を厳密に確認したい場合は、単に変換するだけでなく、どこまで変換されたかを確認する必要があります。
実用的には入力チェックが重要
コマンドライン引数は、ユーザーが自由に入力できる値です。
そのため、プログラム側では、想定外の入力が来ることを前提にしておくべきです。
特に、次のようなケースには注意が必要です。
引数が足りない場合、引数が多すぎる場合、数値ではない値が渡された場合、数値が大きすぎる場合、必須オプションが指定されていない場合などです。
これらを適切にチェックすることで、プログラムの信頼性が高くなります。
引数の数を確認する考え方
コマンドライン引数を使う場合、最初に確認すべきなのが引数の数です。
必要な引数が足りない状態で処理を進めると、エラーや不正な動作の原因になります。
最低限の数だけ確認する場合
「少なくともこの数の引数が必要」という場合は、最低限の数を満たしているかを確認します。
たとえば、入力ファイル名だけが必要なプログラムであれば、ユーザーが少なくとも1つの引数を指定しているか確認します。
この場合、余分な引数があっても無視する設計にすることもできます。
引数の数を厳密に確認する場合
一方で、「引数は必ず2つだけ」と決めたい場合もあります。
たとえば、入力ファイルと出力ファイルを1つずつ指定するプログラムでは、ユーザーが余計な引数を指定した場合もエラーにしたほうが分かりやすいことがあります。
このような場合は、引数が足りないかどうかだけでなく、多すぎないかどうかも確認します。
どちらがよいかは仕様による
引数の数をどの程度厳密に確認するかは、プログラムの仕様によって変わります。
簡単なサンプルプログラムでは、引数が足りない場合だけ確認すれば十分なこともあります。
しかし、実用的なコマンドラインツールでは、余分な引数や不明な引数をエラーとして扱うほうが親切です。
オプション引数とは
コマンドライン引数には、値を順番で指定する方法だけでなく、名前付きで指定する方法もあります。
このような名前付きの引数を、一般的にオプション引数と呼びます。
オプション引数のメリット
オプション引数を使うと、引数の意味が分かりやすくなります。
たとえば、入力ファイル、出力ファイル、詳細表示の有無などを指定する場合、単に値を並べるよりも、名前付きで指定したほうが読みやすくなります。
また、順番に依存しにくくなるため、ユーザーにとっても扱いやすくなります。
よく使われる形式
コマンドラインツールでは、長いオプションと短いオプションがよく使われます。
長いオプションは、意味が分かりやすい名前を使います。
短いオプションは、入力を簡単にするために1文字で指定することが多いです。
たとえば、ヘルプ表示、詳細表示、入力ファイル指定、出力ファイル指定などは、コマンドラインツールでよく使われるオプションです。
フラグ引数とは
フラグ引数とは、値を持たず、有効か無効かだけを表す引数です。
たとえば、詳細表示モードを有効にする、デバッグモードを有効にする、確認なしで実行する、といった用途で使われます。
フラグ引数の特徴
フラグ引数は、指定されていれば有効、指定されていなければ無効として扱うのが一般的です。
値を受け取るオプションとは異なり、次の引数を値として読み取る必要がありません。
そのため、処理としては比較的シンプルです。
実用例
実用的なプログラムでは、詳細なログを表示するためのフラグ、処理内容を確認するだけのフラグ、上書きを許可するフラグなどがよく使われます。
このようなフラグを用意すると、プログラムを柔軟に操作できるようになります。
–helpを用意すると使いやすくなる
コマンドラインツールでは、--help のようなヘルプ表示用のオプションを用意することが多いです。
ヘルプ表示の役割
ヘルプ表示には、プログラムの使い方、指定できるオプション、必須の引数、実行例などを記載します。
ユーザーが使い方を忘れたときや、初めて使うときに確認できるため、非常に重要です。
エラー時にも案内すると親切
不明な引数が指定された場合や、必須の引数が足りない場合には、単にエラーを表示するだけでなく、ヘルプの見方を案内すると親切です。
たとえば、「使い方を確認するには --help を指定してください」のような案内があると、ユーザーは次に何をすればよいか分かりやすくなります。
スペースを含む引数の扱い
コマンドライン引数は、基本的にスペースで区切られます。
そのため、スペースを含む文字列を1つの引数として渡したい場合は、引用符で囲む必要があります。
スペースで区切られる仕組み
たとえば、2つの単語をスペースで区切って指定すると、プログラム側では2つの引数として扱われます。
一方、引用符で囲むと、スペースを含んだ1つの文字列として扱われます。
これは、名前、文章、ファイル名、フォルダ名などを引数として渡すときに重要です。
ファイル名にスペースがある場合
ファイル名やフォルダ名にスペースが含まれている場合も、引用符で囲む必要があります。
引用符で囲まないと、ファイル名の途中で別々の引数として分割されてしまい、正しく処理できない場合があります。
特にWindowsでは、フォルダ名やファイル名にスペースが含まれることが多いため注意が必要です。
日本語などの文字を渡す場合の注意点
コマンドライン引数として、日本語を渡すこともできます。
ただし、日本語などのマルチバイト文字やUnicode文字を扱う場合は、文字コードに注意が必要です。
LinuxやmacOSの場合
LinuxやmacOSでは、UTF-8環境で動作していることが多いため、日本語の引数を比較的扱いやすい場合が多いです。
ただし、ターミナルの設定やロケール設定によっては、表示が崩れる可能性もあります。
Windowsの場合
Windowsでは、通常のコマンドライン引数の受け取り方だと、日本語が文字化けする場合があります。
これは、Windows内部の文字の扱い、コンソールの文字コード、C++ランタイムの処理、表示側の設定などが関係するためです。
そのため、Windowsで日本語やUnicode文字を確実に扱いたい場合は、通常の main だけでなく、Windows向けの入口や文字コード変換を検討することがあります。
受け取りと表示は別問題
日本語引数を扱うときは、「プログラムが正しく受け取れるか」と「画面に正しく表示できるか」を分けて考える必要があります。
たとえ内部的に正しく受け取れていても、コンソールの設定によっては表示が文字化けすることがあります。
逆に、表示はできていても、内部の文字列処理で想定外の問題が起きる場合もあります。
Windowsのwmainについて
Windowsでは、日本語などのUnicode引数を扱う方法として、wmain が使われることがあります。
wmainは標準C++ではない
wmain は、標準C++で定められている一般的な main 関数の形式ではありません。
主にMicrosoft Visual C++など、Windows向けの環境で使われる仕組みです。
そのため、すべてのC++コンパイラやすべてのOSで使えるわけではありません。
Windows向けプログラムでは選択肢になる
Windows専用のプログラムで、コマンドライン引数として日本語やUnicode文字を確実に扱いたい場合、wmain は選択肢の1つになります。
ただし、wmain を使えば必ずすべて解決するわけではありません。
表示側の文字コード、コンソールの設定、出力方法などにも注意が必要です。
コマンドライン引数と標準入力の違い
コマンドライン引数と標準入力は、どちらもプログラムに値を渡す方法ですが、使い方が異なります。
コマンドライン引数
コマンドライン引数は、プログラムを実行するときにあらかじめ指定する値です。
ファイル名、処理モード、オプション、設定値など、実行前に決まっている情報を渡すのに向いています。
標準入力
標準入力は、プログラムの実行中に入力を受け取る仕組みです。
キーボードから入力するだけでなく、ファイルのリダイレクトや他のコマンドからのパイプ入力を受け取ることもできます。
使い分けの目安
実行時にあらかじめ決まっている設定やファイル名は、コマンドライン引数が向いています。
一方、処理対象のデータそのものを流し込む場合や、ユーザーと対話しながら入力を受け取りたい場合は、標準入力が向いています。
たとえば、ファイル変換ツールでは入力ファイル名や出力ファイル名をコマンドライン引数で指定することが多いです。
一方、複数行のテキストを処理するツールでは、標準入力からデータを受け取る設計もよく使われます。
エラー出力にはstd::cerrを使うとよい
C++では、通常の出力には std::cout、エラー出力には std::cerr を使うのが一般的です。
std::coutとstd::cerrの違い
std::cout は、通常の結果を出力するために使います。
一方、std::cerr は、エラーメッセージや警告を出力するために使います。
初心者向けの簡単なサンプルでは、すべて std::cout で表示しても理解しやすいですが、実用的なコマンドラインツールでは分けて使うのが望ましいです。
出力を分けるメリット
通常の出力とエラー出力を分けると、リダイレクトやパイプ処理をしやすくなります。
たとえば、正常な処理結果だけをファイルに保存し、エラーは画面に表示する、といった使い方ができます。
コマンドラインツールを作る場合は、出力先の使い分けも意識すると、より実用的なプログラムになります。
main関数の戻り値
コマンドライン引数を扱うプログラムでは、main 関数の戻り値も重要です。
正常終了と異常終了
一般的に、main 関数が 0 を返すと正常終了を意味します。
一方、0 以外の値を返すと、エラーや異常終了を表す終了コードとして扱われます。
終了コードが重要になる場面
終了コードは、シェルスクリプトやバッチファイル、他のプログラムから実行されたときに重要になります。
プログラムが正常に完了したのか、エラーで終了したのかを外部から判断できるためです。
たとえば、引数が足りない場合、ファイルを開けなかった場合、不正な値が指定された場合などは、エラーを表す終了コードを返すのが自然です。
argv[argc]について
argv には、引数の文字列が順番に入ります。
そして、argv[argc] はヌルポインタになります。
argv[argc]の意味
argc は引数の個数を表します。
配列の添字は0から始まるため、有効な引数は argv[0] から argv[argc - 1] までです。
その次にあたる argv[argc] は、引数の終端を表すヌルポインタになります。
通常は意識しなくてもよい
argv[argc] がヌルポインタになることは仕様として知っておくと役立ちます。
ただし、通常の処理では、argc を使って範囲内だけを処理すれば十分です。
初心者のうちは、argv[argc] を直接使うよりも、argc で引数の数を確認しながら安全に処理することを優先するとよいでしょう。
char* argv[]とchar** argvの違い
C++の main 関数では、コマンドライン引数を受け取る形として、char* argv[] や char** argv が使われます。
実質的には同じように扱える
関数の引数として書かれた配列は、ポインタとして扱われます。
そのため、char* argv[] と char** argv は、コマンドライン引数を受け取るという意味では実質的に同じように扱えます。
初心者にはchar* argv[]が分かりやすい
初心者の場合は、char* argv[] のほうが「文字列が並んだ配列」というイメージを持ちやすいです。
そのため、最初に学ぶときは argc と argv の組み合わせで覚えると理解しやすいでしょう。
argvの中身は基本的に書き換えない
argv の各要素は文字列として扱えますが、基本的には読み取り専用のものとして扱うのが安全です。
書き換えは避けたほうがよい
argv の中身を書き換えるような処理は、環境や実装によって問題になる可能性があります。
そのため、引数の文字列を加工したい場合は、直接 argv を変更するのではなく、いったんC++の文字列としてコピーしてから扱うのが一般的です。
std::stringに変換すると扱いやすい
C++では、引数を std::string として扱うと、比較、検索、分割、長さの確認などがしやすくなります。
そのため、実用的なプログラムでは、argv から受け取った文字列を std::string に変換して処理することが多いです。
コマンドライン引数でよくあるミス
コマンドライン引数は便利ですが、初心者がつまずきやすいポイントもあります。
argv[0]を最初の引数だと思ってしまう
もっともよくあるミスの1つが、argv[0] をユーザーが指定した最初の引数だと思ってしまうことです。
実際には、argv[0] は通常プログラム名です。
ユーザーが指定した最初の引数は argv[1] です。
argcの確認を忘れる
引数が指定されているか確認せずに argv[1] や argv[2] を使うと危険です。
引数が足りない場合、存在しない要素を参照することになり、プログラムが異常終了する可能性があります。
コマンドライン引数を使うときは、必ず必要な数の引数があるか確認しましょう。
数値変換を忘れる
コマンドライン引数は、数値に見えても最初は文字列として渡されます。
そのため、計算に使いたい場合は数値へ変換する必要があります。
変換せずに文字列として扱うと、期待した計算ができません。
スペースを含む引数を引用符で囲まない
スペースを含む文字列を1つの引数として渡したい場合は、引用符で囲む必要があります。
引用符で囲まないと、スペースの位置で複数の引数に分割されてしまいます。
不明な引数を無視してしまう
実用的なプログラムでは、不明な引数を無視するよりも、エラーとして扱うほうが親切です。
ユーザーが入力ミスをしていた場合、無視して処理を続けると、意図しない結果になる可能性があります。
不明な引数を検出し、分かりやすいメッセージを表示すると、使いやすいプログラムになります。
コマンドライン引数を使うメリット
コマンドライン引数を使うと、プログラムの使い勝手が大きく向上します。
プログラムを書き換えずに動作を変えられる
コマンドライン引数を使えば、実行時に処理対象や設定を変更できます。
たとえば、読み込むファイル、出力先、処理モード、ログの詳しさなどを外部から指定できます。
これにより、同じプログラムをさまざまな条件で使い回せます。
自動化しやすい
コマンドライン引数に対応しているプログラムは、シェルスクリプトやバッチ処理に組み込みやすくなります。
定期実行、複数ファイルの一括処理、他のツールとの連携などにも向いています。
ツールとして使いやすくなる
コマンドライン引数を適切に設計すると、プログラムを小さなツールとして使いやすくなります。
特に、ファイル処理、データ変換、ログ解析、テスト実行などの用途では、コマンドライン引数があると非常に便利です。
実用的な引数設計のポイント
コマンドライン引数を使うときは、単に値を受け取るだけでなく、使いやすさも意識するとよいです。
必須引数と任意引数を分ける
必ず指定しなければならない引数と、省略できる引数を分けて考えます。
たとえば、入力ファイルは必須、詳細表示は任意というように設計すると、プログラムの仕様が分かりやすくなります。
エラーメッセージを分かりやすくする
引数が足りない場合や不正な値が指定された場合は、原因が分かるメッセージを表示します。
「エラー」とだけ表示するのではなく、「どの引数が足りないのか」「どの値が不正なのか」を伝えると親切です。
ヘルプを用意する
使い方を確認できるヘルプを用意すると、ユーザーにとって使いやすいプログラムになります。
ヘルプには、引数の意味、指定できるオプション、簡単な実行例を含めるとよいでしょう。
複雑な場合はライブラリを使う
簡単な引数であれば、自分で処理しても問題ありません。
しかし、オプションが増えたり、サブコマンドを扱ったり、必須・任意の設定が複雑になったりする場合は、引数解析ライブラリを使う選択肢もあります。
ライブラリを使うと、ヘルプ表示やエラーチェックを整えやすくなります。
まとめ
C++のコマンドライン引数は、プログラムを実行するときに外部から値を渡すための仕組みです。
argc は引数の個数を表し、argv は引数の中身を表します。
通常、argv[0] にはプログラム名や実行時に指定されたパスが入り、ユーザーが指定した最初の引数は argv[1] に入ります。
コマンドライン引数は基本的に文字列として渡されるため、数値として使う場合は変換が必要です。
また、引数が足りない場合や不正な値が渡された場合に備えて、入力チェックやエラー処理を行うことも重要です。
実用的なプログラムでは、--help、--verbose、入力ファイル指定、出力ファイル指定などのオプションを用意すると、使いやすいコマンドラインツールになります。
また、日本語などの文字を扱う場合は、OSやコンソールの文字コード設定にも注意が必要です。
特にWindowsでは、受け取り方と表示方法の両方を意識する必要があります。
C++でコマンドライン引数を扱う基本は、難しくありません。
まずは argc で引数の数を確認し、argv から必要な値を取り出す流れを理解することが大切です。
そのうえで、数値変換、エラー処理、オプション設計を加えていくと、実用的なコマンドラインプログラムを作れるようになります。
以上、C++のコマンドライン引数についてでした。
最後までお読みいただき、ありがとうございました。
