211

プログラムが次のように実行されるように指定されている場合、C++ でコマンドライン引数を解析する最良の方法は何ですか?

prog [-abc] [input [output]]

標準ライブラリに組み込まれているこれを行う方法はありますか、それとも独自のコードを記述する必要がありますか?


関連している:

4

42 に答える 42

89

Boost.Program_options はトリックを行う必要があります

于 2009-05-14T20:49:37.383 に答える
63

テンプレート化された C++ コマンド ライン パーサー ライブラリ( GitHub のいくつかのフォークが利用可能)を提案できます。API は非常に簡単で、(サイトから引用):

ライブラリは完全にヘッダー ファイルに実装されているため、使いやすく、他のソフトウェアと一緒に配布することもできます。安心して配布できるように、MIT ライセンスの下でライセンスされています。

これはマニュアルの例で、わかりやすくするためにここに色を付けています。

#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>

int main(int argc, char** argv)
{

    // Wrap everything in a try block.  Do this every time,
    // because exceptions will be thrown for problems.
    try {

    // Define the command line object, and insert a message
    // that describes the program. The "Command description message"
    // is printed last in the help text. The second argument is the
    // delimiter (usually space) and the last one is the version number.
    // The CmdLine object parses the argv array based on the Arg objects
    // that it contains.
    TCLAP::CmdLine cmd("Command description message", ' ', "0.9");

    // Define a value argument and add it to the command line.
    // A value arg defines a flag and a type of value that it expects,
    // such as "-n Bishop".
    TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");

    // Add the argument nameArg to the CmdLine object. The CmdLine object
    // uses this Arg to parse the command line.
    cmd.add( nameArg );

    // Define a switch and add it to the command line.
    // A switch arg is a boolean argument and only defines a flag that
    // indicates true or false.  In this example the SwitchArg adds itself
    // to the CmdLine object as part of the constructor.  This eliminates
    // the need to call the cmd.add() method.  All args have support in
    // their constructors to add themselves directly to the CmdLine object.
    // It doesn't matter which idiom you choose, they accomplish the same thing.
    TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);

    // Parse the argv array.
    cmd.parse( argc, argv );

    // Get the value parsed by each arg.
    std::string name = nameArg.getValue();
    bool reverseName = reverseSwitch.getValue();

    // Do what you intend.
    if ( reverseName )
    {
            std::reverse(name.begin(),name.end());
            std::cout << "My name (spelled backwards) is: " << name << std::endl;
    }
    else
            std::cout << "My name is: " << name << std::endl;


    } catch (TCLAP::ArgException &e)  // catch any exceptions
    { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}
于 2011-10-10T11:54:05.793 に答える
45

Boost.Program_options

于 2008-10-31T14:02:56.093 に答える
37

GNU GetOpt (LGPL) またはgetoptpp (GPL)などのさまざまな C++ ポートのいずれかを使用できます。

必要なものの GetOpt を使用した簡単な例 ( prog [-ab] input ) は次のとおりです。

// C Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    string input = "";
    bool flagA = false;
    bool flagB = false;

    // Retrieve the (non-option) argument:
    if ( (argc <= 1) || (argv[argc-1] == NULL) || (argv[argc-1][0] == '-') ) {  // there is NO input...
        cerr << "No argument provided!" << endl;
        //return 1;
    }
    else {  // there is an input...
        input = argv[argc-1];
    }

    // Debug:
    cout << "input = " << input << endl;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}
于 2009-05-14T20:49:55.073 に答える
27

GNU GetOpt .

GetOpt を使用した簡単な例:

// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    bool flagA = false;
    bool flagB = false;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}

引数を受け入れるオプションがある場合は、optargを使用することもできます。

于 2008-10-31T14:12:30.270 に答える
23

さらに別の選択肢として、The Lean Mean C++ Option Parser があります。

http://optionparser.sourceforge.net

これはヘッダーのみのライブラリ (実際には 1 つのヘッダー ファイルのみ) であり、他のすべての提案とは異なり、独立型でもあります。つまり、依存関係はまったくありません。特に、STL への依存はありません。ライブラリのサポートを必要とする例外やその他のものも使用しません。これは、「外国の」ライブラリを導入することなく、プレーン C または他の言語とリンクできることを意味します。

boost::program_options と同様に、その API はオプションへの便利な直接アクセスを提供します。つまり、次のようなコードを記述できます。

if (オプション[ヘルプ]) ... ;

int verbosity = options[VERBOSE].count();

boost::program_options とは異なり、これは単純に (ユーザー提供の) 列挙型でインデックス付けされた配列を使用しています。これにより、重量のない連想コンテナの利便性が提供されます。

それは十分に文書化されており、企業向けのライセンス (MIT) を持っています。

TLMC++OP には、行の折り返しと列の配置を行うことができる使用法メッセージ用の優れたフォーマッタが含まれています。これは、プログラムをローカライズする場合に役立ちます。これにより、メッセージが長い言語でも出力が適切に表示されることが保証されるためです。また、80 列の使用法を手動でフォーマットする手間も省けます。

于 2012-01-24T18:12:37.777 に答える
21
for (int i = 1; i < argc; i++) {

    if (strcmp(argv[i],"-i")==0) {
        filename = argv[i+1];
        printf("filename: %s",filename);
    } else if (strcmp(argv[i],"-c")==0) {
        convergence = atoi(argv[i + 1]);
        printf("\nconvergence: %d",convergence);
    } else if (strcmp(argv[i],"-a")==0) {
        accuracy = atoi(argv[i + 1]);
        printf("\naccuracy:%d",accuracy);
    } else if (strcmp(argv[i],"-t")==0) {
        targetBitRate = atof(argv[i + 1]);
        printf("\ntargetBitRate:%f",targetBitRate);
    } else if (strcmp(argv[i],"-f")==0) {
        frameRate = atoi(argv[i + 1]);
        printf("\nframeRate:%d",frameRate);
    }

}
于 2011-08-04T23:24:53.920 に答える
19

TCLAP本当に素晴らしい軽量設計で使いやすいです: http://tclap.sourceforge.net/

于 2012-08-22T22:37:46.947 に答える
18

おそらく、そのために外部ライブラリを使用したいと思うでしょう。選択できるものはたくさんあります。

Boost には非常に機能豊富な (いつものように) ライブラリBoost Program Optionsがあります。

ここ数年の私の個人的なお気に入りはTCLAP です。完全にテンプレート化されているため、ライブラリやリンクはなく、自動化された「--help」生成やその他の利点があります。ドキュメントの最も単純な例を参照してください。

于 2010-09-30T00:35:34.357 に答える
18

コマンドラインオプションを自分で処理したいだけの場合、最も簡単な方法は次のとおりです。

vector<string> args(argv + 1, argv + argc);

の上部にありますmain()。これにより、すべてのコマンドライン引数がstd::strings のベクトルにコピーされます。次に、無限の呼び出し==の代わりに、文字列を簡単に比較するために使用できます。strcmp()例えば:

int main(int argc, char **argv) {
    vector<string> args(argv + 1, argv + argc);
    string infname, outfname;

    // Loop over command-line args
    // (Actually I usually use an ordinary integer loop variable and compare
    // args[i] instead of *i -- don't tell anyone! ;)
    for (auto i = args.begin(); i != args.end(); ++i) {
        if (*i == "-h" || *i == "--help") {
            cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
            return 0;
        } else if (*i == "-i") {
            infname = *++i;
        } else if (*i == "-o") {
            outfname = *++i;
        }
    }
}

[編集:argv[0]プログラムの名前である をargs-- 修正済みにコピーしていることに気付きました。]

于 2009-01-14T06:50:32.050 に答える
16

Google ライブラリも利用できます。

本当に、コマンドライン解析は「解決」されています。1つだけ選んでください。

于 2008-10-31T16:46:05.717 に答える
15

C++ の場合、答えは通常 Boost にあります...

Boost.Program オプション

于 2009-01-14T01:17:28.977 に答える
11

Boost::Program Optionsを試してください。コマンドラインと構成ファイルを読み取って解析できます。

于 2009-09-17T03:18:46.133 に答える
8

これらのツールは、 GetOptを含む GNU C ライブラリにあります。

Qt を使用していて、GetOpt インターフェイスが好きな場合、froglogicはこちらで素敵なインターフェイスを公開しています。

于 2008-10-31T14:19:07.497 に答える
7

可能であれば、自分のホーンを鳴らして、私が書いたオプション解析ライブラリを見てみることをお勧めします:dropt

  • これはCライブラリです(必要に応じてC ++ラッパーを使用)。
  • 軽量です。
  • これは拡張可能です(カスタム引数タイプは簡単に追加でき、組み込みの引数タイプと同等の基盤を持つことができます)。
  • 依存関係(C標準ライブラリ以外)がなく、非常に移植性が高い(標準Cで記述されている)必要があります。
  • 非常に制限のないライセンス(zlib / libpng)があります。

他の多くの機能にはない機能の1つは、以前のオプションをオーバーライドする機能です。たとえば、シェルエイリアスがある場合:

alias bar="foo --flag1 --flag2 --flag3"

使用したいbar--flag1無効にすると、次のことが可能になります。

bar --flag1=0
于 2012-10-03T06:11:24.797 に答える
6

Google のgflags

于 2009-09-17T03:20:12.230 に答える
6

私は C の getopt() が好きですが、私は年をとっています。:-)

于 2009-09-17T03:19:02.277 に答える
5

利用可能な優れたライブラリがいくつかあります。

Boost Program Optionsはかなり重いソリューションです。これは、Boost Program Optionsをプロジェクトに追加するには、Boostをビルドする必要があり、構文がやや混乱するためです(私の意見では)。ただし、コマンドラインオプションで構成ファイルに設定されているオプションを上書きするなど、ほとんどすべてのことを実行できます。

SimpleOptは、かなり包括的ですがシンプルなコマンドラインプロセッサです。これは単一のファイルであり、構造は単純ですが、コマンドラインのオプションへの解析のみを処理するため、すべてのタイプと範囲のチェックを行う必要があります。これはWindowsとUnixの両方に適しており、Windows用のglobのバージョンも付属しています。

getoptはWindowsで利用できます。Unixマシンと同じですが、多くの場合GPLライブラリです。

于 2009-04-21T08:45:02.350 に答える
5

AnyOptionは、複雑なコマンドライン オプションを簡単に解析するための C++ クラスです。また、オプション値のペア形式で rsourcefile からオプションを解析します。

AnyOption は、従来の POSIX スタイルの文字オプション ( -n ) と新しい GNU スタイルの長いオプション ( --name ) を実装します。または、POSIX スタイルのオプションを無視するように要求することで、より単純な長いオプション バージョン ( -name ) を使用できます。

于 2011-08-17T15:23:19.390 に答える
5

ライブラリを使用することをお勧めします。古典的で由緒あるgetoptがあり、他にもあると思います。

于 2009-01-14T01:18:22.970 に答える
3

これには、すでに作成されたライブラリを使用できます

http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html

于 2010-09-30T00:35:51.490 に答える
3

CLPP ライブラリを試してください。コマンド ライン パラメーターを解析するためのシンプルで柔軟なライブラリです。ヘッダーのみでクロスプラットフォーム。ISO C++ および Boost C++ ライブラリのみを使用します。私見では、Boost.Program_options よりも簡単です。

ライブラリ: http://sourceforge.net/projects/clp-parser/

2010 年 10 月 26 日 - 新しいリリース 2.0rc。多くのバグが修正され、ソース コード、ドキュメント、サンプル、コメントの完全なリファクタリングが修正されました。

于 2010-05-03T10:54:27.567 に答える
3

Boost ライブラリを使用できる場合は、boost::program_options をお勧めします。

STL にも通常の C++/C ランタイム ライブラリにも固有のものはありません。

于 2009-05-14T20:50:00.533 に答える
3

argstreamと非常によく似てboost.program_optionいます。変数をオプションなどにバインドできます。ただし、構成ファイルに保存されているオプションは処理しません。

于 2008-10-31T14:26:29.213 に答える
2

これが linux/unix の場合、使用する標準的なものは gnu getopt です。

http://www.gnu.org/s/libc/manual/html_node/Getopt.html

于 2010-09-30T00:37:33.423 に答える
2

CLPP ライブラリを試してください。コマンド ライン パラメーターを解析するためのシンプルで柔軟なライブラリです。ヘッダーのみでクロスプラットフォーム。ISO C++ および Boost C++ ライブラリのみを使用します。私見では、Boost.Program_options よりも簡単です。

ライブラリ: http://sourceforge.net/projects/clp-parser

2010 年 10 月 26 日 - 新しいリリース 2.0rc。多くのバグが修正され、ソース コード、ドキュメント、サンプル、コメントの完全なリファクタリングが修正されました。

于 2010-05-03T10:50:04.113 に答える
2

私はいくつかのプロジェクトで GetPot を使用しました: http://getpot.sourceforge.net/

主な機能: すべてが単一のヘッダー ファイルにあり、ビルドの手間がかかりません。マシンのどこかに保存し、ファイル保持に「#include」するだけですmain()

最近更新されていませんが、適切に文書化されており、うまく機能します。

于 2011-04-20T19:31:45.317 に答える
2

これは、特にコマンド ラインを実行する私のお気に入りの方法ですが、効率が問題になる場合だけではありません。やり過ぎと思われるかもしれませんが、このやり過ぎによるデメリットは少ないと思います。

効率的な C/C++ コマンド ライン処理のために gperf を使用する

短所:

  • C/C++ でハッシュ テーブルのコードを生成するには、最初に別のツールを実行する必要があります。
  • 特定のコマンド ライン インターフェイスはサポートされていません。たとえば、1 つのダッシュで複数のオプションを宣言する posix 短縮形システム "-xyz" は実装が難しいでしょう。

利点:

  • コマンド ライン オプションは、C++ コードとは別に保存されます (別の構成ファイルに保存されます。このファイルは、実行時に読み取る必要はなく、コンパイル時にのみ読み取る必要があります)。
  • コードにあるのは、どのオプションがあるかを把握するための 1 つのスイッチ (列挙値の切り替え) だけです。
  • 効率は O(n) です。ここで、n はコマンド ラインのオプションの数であり、可能なオプションの数は関係ありません。最も遅い部分は、おそらくスイッチの実装です (コンパイラは、else ブロックのようにそれらを実装する傾向があり、効率を低下させますが、連続した値を選択した場合、これは起こりそうにありません。スイッチの効率に関するこの記事を参照してください) 。
  • キーワードを格納するために割り当てられたメモリは、キーワード セットに対して正確に十分な大きさであり、それ以上ではありません。
  • Cでも動作します

eclipse のような IDE を使用すると、おそらく gperf の実行プロセスを自動化できるため、設定ファイルと switch ステートメントにオプションを追加し、ビルドを押すだけで済みます...

バッチファイルを使用してgperfを実行し、クリーンアップを行い、sedを使用してインクルードガードを追加しました(gperfで生成された.hppファイルに)...

したがって、ソフトウェア内の非常に簡潔でクリーンなコードと、手動で変更する必要のない 1 つの自動生成されたハッシュ テーブル ファイルです。優先事項として効率がなくても、boost::program_optionsが実際にそれを打ち負かすかどうかは疑問です。

于 2010-06-21T11:54:55.790 に答える
2

program_options をブーストします。

于 2009-09-17T03:19:19.767 に答える
1

私のコメントとrbaleksandarの回答に続いて、Cのプログラムに渡される引数は文字列値です。現在実行中のプログラムの名前 (常に ) で始まるゼロベースの引数インデックスを与える引数 count ( )が提供されます。これにより、ユーザーがプログラムに提供した引数として、その間のすべての引数が残ります。それぞれは、引数ベクトルに含まれる文字列になります(これは、文字列の配列へのポインターであり、関数パラメーターとして記述されます) 。どの引数がどれです。argcargv[0]1 - argcchar *argv[]char **argvargv[1]argv[argc-1]

これにより、それらを分離して、コマンド( cmd)、オプション( opt)、最後に引数( arg) として使用できるようになりますcmd

ここで、シェル (bash など) の規則がプログラムに渡される引数に適用されることに注意してください。word-splittingpathname、および変数展開は、コードが引数を取得する前に適用されます。したがって、通常のシェル分割を防ぐために、引数の周りに単一またはより一般的に二重引用ls -al my file.txt符を付ける必要があるかどうかを検討する必要があります (たとえば、4ユーザーがコードに引数を指定することになり、 whilels -al "my file.txt"またはls -al my\ file.txtは、3あなたは期待していました。

これらすべてをまとめると、短い構文解析は次のようになります。switch(ネストされた s の代わりにa を使用するなど、好きなように自由に行うこともできますif...)

#include <stdio.h>

int main (int argc, char **argv) {

    char *cmd = NULL,   /* here, since you are using the arguments  */
         *opt = NULL,   /* themselves, you can simply use a pointer */
         *arg = NULL;   /* or the argument itself without a copy    */

    /* looping using the acutal argument index & vector */
    for (int i = 1; i < argc; i++) {
        if (*argv[i] != '-') {      /* checking if the 1st char is - */
            if (!cmd)               /* cmd is currently NULL, and    */
                cmd = argv[i];      /* no '-' it's going to be cmd   */
            else                    /* otherwise, cmd has value, so  */
                arg = argv[i];       /* the value will be opt        */
        }
        else                /* here the value has a leading '-', so  */
            opt = argv[i];  /* it will be the option */
    }

    printf ("\n cmd : %s\n opt : %s\n arg : %s\n\n",
            cmd, opt, arg);

    return 0;
}

使用例/出力

コードを実行すると、引数が分離され、使いやすいように別のポインターが提供されることがわかります。

$ ./bin/parse_cmd ls -la ./cs3000

 cmd : ls
 opt : -la
 arg : ./cs3000

opt(複数の値をorにコピーする必要があるコマンド文字列を作成するタスクを課された場合arg、ポインタを単純に使用することはできなくなり、ストレージを作成する必要があることに注意してください。最初はポインタの代わりに配列を使用するか、必要に応じてmalloccallocおよび/または などを使用して動的にストレージを割り当てることができますrealloc。そうすれば、ストレージ内で値をコピーおよび連結するために使用できるストレージが得られます。)

これがあなたの課題だった場合、ここにあるすべての答えの中で、問題へのアプローチ方法を理解する必要があります。さらに進んで、実際にプログラムに と を実行させる必要がある場合は、実行cmdする半分離プロセスを生成して、またはに似たもので andoptを実行することを検討する必要があります。さらに質問がある場合は、コメントを投稿してください。argforkcmd optargexecvexecvp

于 2016-09-15T08:57:23.710 に答える
0

CLPPライブラリを試してください。これは、コマンドラインパラメータを解析するためのシンプルで柔軟なライブラリです。ヘッダーのみおよびクロスプラットフォーム。ISOC++およびBoostC++ライブラリのみを使用します。私見では、Boost.Program_optionsよりも簡単です。

ライブラリ:http ://sourceforge.net/projects/clp-parser

2010年10月26日-新しいリリース2.0rc。多くのバグが修正され、ソースコード、ドキュメント、例、コメントの完全なリファクタリングが修正されました。

于 2010-10-27T04:04:21.823 に答える
0

C/C++ プログラムには常に main 関数があります。次のようになります。

    int main(int argc, char**argv) {
        ...
    }

ここで、argc はプログラムに渡されたコマンド ライン引数の数であり、argv はこれらの引数を含む文字列の配列です。そのため、コマンド ラインは、呼び出し元プロセスによって引数に分割されます (これは、Windows のように 1 行ではありません)。

次に、それらを整理する必要があります。

  • コマンド名は常に最初の引数 (インデックス 0) です。
  • オプションは、プログラムがどのように動作するかを指定する特別な引数です。慣例により、それらは - 記号から始まります。通常 - 1 文字のオプションの場合、および -- より長いオプションの場合。したがって、タスクの「オプション」はすべての引数であり、- から始まり、0 番目ではありません。
  • 引数。プログラム名またはオプションではない他のすべての引数。
于 2016-09-15T07:09:44.760 に答える
0

ブーストを使用したくない場合は、この小さなヘルパー クラスをお勧めします。

于 2009-01-14T06:47:12.260 に答える