18

さまざまなコマンドライン引数を取るプログラムがあります。-a簡単にするために、 、-b、およびの3 つのフラグが必要であると言い-c、次のコードを使用して引数を解析します。

    int c;
    while((c =  getopt(argc, argv, ":a:b:c")) != EOF)
    {
        switch (c)
        {
             case 'a':
                 cout << optarg << endl;
                 break;
             case 'b':
                 cout << optarg << endl;
                 break;
             case ':':
                 cerr << "Missing option." << endl;
                 exit(1);
                 break;
        }
    }

注: a と b は、フラグの後にパラメーターを取ります。

しかし、プログラムを次のように呼び出すと、問題が発生します

./myprog -a -b parameterForB

ここで、parameterForA を忘れました。parameterForA (optarg で表される) が返され-b、parameterForB はパラメーターのないオプションと見なされ、optind は argv の parameterForB のインデックスに設定されます。

この状況で望ましい動作は':'、 の引数が見つからなかった後に が返され-aMissing option.標準エラーに出力されることです。ただし、これ-aは、プログラムに渡された最後のパラメーターであるイベントでのみ発生します。

問題は次のとおりだと思います。getopt()オプションが で始まらないと仮定する方法はあります-か?

4

5 に答える 5

12

のPOSIX 標準定義を参照してくださいgetopt。それは言う

[getopt] がオプション引数の欠落を検出すると、optstring の最初の文字がコロンの場合はコロン文字 ( ':' ) を返し、それ以外の場合は疑問符文字 ( '?' ) を返します。

その検出に関しては、

  1. オプションが argv の要素によって指される文字列の最後の文字である場合、optarg には argv の次の要素が含まれ、optind は 2 だけインクリメントされます。optind の結果の値が argc より大きい場合、これはオプション引数が欠落しており、getopt() はエラー表示を返すものとします。
  2. それ以外の場合、optarg は argv のその要素内のオプション文字に続く文字列を指し、optind は 1 ずつインクリメントされます。

getoptあなたが望むことをしないように定義されているように見えるので、自分でチェックを実装する必要があります。幸いなことに、自分自身を調べ*optargて変更することでそれを行うことができoptindます。

int c, prev_ind;
while(prev_ind = optind, (c =  getopt(argc, argv, ":a:b:c")) != EOF)
{
    if ( optind == prev_ind + 2 && *optarg == '-' ) {
        c = ':';
        -- optind;
    }
    switch ( …
于 2010-02-08T05:12:19.777 に答える
7

C ++で作業している場合は、boost::program_optionがコマンドライン引数を解析するための私の推奨事項です。

于 2010-02-08T04:43:54.863 に答える
4

完全な開示: 私はこの問題の専門家ではありません。

gnu.org のこの例は役に立ちますか? 「?」を処理するようです 予期される引数が指定されなかった場合の文字:

while ((c = getopt (argc, argv, "abc:")) != -1)
    switch (c)
    {
       case 'a':
         aflag = 1;
         break;
       case 'b':
         bflag = 1;
         break;
       case 'c':
         cvalue = optarg;
         break;
       case '?':
         if (optopt == 'c')
           fprintf (stderr, "Option -%c requires an argument.\n", optopt);
         else if (isprint (optopt))
           fprintf (stderr, "Unknown option `-%c'.\n", optopt);
         else
           fprintf (stderr,
                    "Unknown option character `\\x%x'.\n",
                    optopt);
         return 1;
       default:
         abort ();
    }

更新:おそらく、以下は修正として機能しますか?

while((c =  getopt(argc, argv, ":a:b:c")) != EOF)
{
    if (optarg[0] == '-')
    {
        c = ':';
    }
    switch (c)
    {
        ...
    }
}
于 2010-02-08T04:37:00.610 に答える
2

Boost-free プロジェクトの代替として、getopt(BSD 3-Clause License の下で) の単純なヘッダーのみの C++ ラッパーがあります: https://github.com/songgao/flags.hh

example.ccレポから取得:

#include "Flags.hh"

#include <cstdint>
#include <iostream>

int main(int argc, char ** argv) {
  uint64_t var1;
  uint32_t var2;
  int32_t var3;
  std::string str;
  bool b, help;

  Flags flags;

  flags.Var(var1, 'a', "var1", uint64_t(64), "This is var1!");
  flags.Var(var2, 'b', "var2", uint32_t(32), "var2 haahahahaha...");
  flags.Var(var3, 'c', "var3", int32_t(42), "var3 is signed!", "Group 1");
  flags.Var(str, 's', "str", std::string("Hello!"), "This is a string, and the description is too long to fit in one line and has to be wrapped blah blah blah blah...", "Group 1");
  flags.Bool(b, 'd', "bool", "this is a bool variable", "Group 2");

  flags.Bool(help, 'h', "help", "show this help and exit", "Group 3");

  if (!flags.Parse(argc, argv)) {
    flags.PrintHelp(argv[0]);
    return 1;
  } else if (help) {
    flags.PrintHelp(argv[0]);
    return 0;
  }

  std::cout << "var1: " << var1 << std::endl;
  std::cout << "var2: " << var2 << std::endl;
  std::cout << "var3: " << var3 << std::endl;
  std::cout << "str:  " << str << std::endl;
  std::cout << "b:    " << (b ? "set" : "unset") << std::endl;

  return 0;
}
于 2015-10-09T21:26:37.887 に答える
1

アラウンドにはかなりの数の異なるバージョンがあるgetoptため、1つのバージョンで機能させることができたとしても、回避策が機能しない他のバージョンが少なくとも5つある可能性があります。getoptを使用する圧倒的な理由がない限り、Boost.Program_optionsなどの他の方法を検討します。

于 2010-02-08T04:41:25.473 に答える