最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【整理】getopt()或getopt_long()与optarg

工作和技术 crifan 3933浏览 0评论

[整理]getopt()或getopt_long()与optarg

getopt或getopt_long 是一个Linux下面的库函数,作用就是解析命令行的输入。其目的就是减轻程序员自己的负担,可以直接使用系统提供的库函数,方便、高效和更安全地解析命令行的输入。

如果你编写的应用程序中的输入参数很少,就2,3个,那么就可以自己去判断,类似于:

mtd-util中的flash_erase.c中的。

。。。

if (argc > 2)
   start = strtol(argv[2], NULL, 0);
else
   start = 0;

if (argc > 3)
   count = strtol(argv[3], NULL, 0);
else
   count = 1;

if(argc > 4)
   unlock = strtol(argv[4], NULL, 0);
else
   unlock = 0;
。。。

如果选项和参数很多,那么自己去一个个判断,效率就太低了,而且也容易出错,那么就可以利用getopt或getopt_long函数了。

先转帖一些相关知识:

  int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
  说明:函数中的argc和argv通常直接从main()到两个参数传递而来。optsting是选项参数组成的字符串,如果该字符串里任一字母后有冒号,那么这个选项就要求有参数。下一个参数是指向数组的指针,这个数组是option结构数组,option结构称为长选项表,其声明如下:
  struct option {
  const char *name;
  int has_arg;
  int *flag;
  int val;
  };
  结构中的元素解释如下:
  const char *name:选项名,前面没有短横线。譬如"help"、"verbose"之类。
  int has_arg:描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表:
          符号常量             数值            含义
          no_argument            0            选项没有参数
          required_argument      1            选项需要参数
          optional_argument      2            选项参数是可选的
  int *flag:
  如果该指针为NULL,那么getopt_long返回val字段的值;
  如果该指针不为NULL,那么会使得它所指向的结构填入val字段的值,同时getopt_long返回0
  int val:
  如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,那么该字符就应该与optstring中出现的这个选项的参数相同;
  最后一个参数:longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts中的索引值,这可以用于错误诊断。

具体用法,给个例子就可以看懂了:
mtd-util中的nandwrite.c :
#include <unistd.h>
#include <getopt.h>
。。。

static const char *standard_input = "-";
static const char *mtd_device, *img;
static int   mtdoffset = 0;
static bool   quiet = false;
static bool   writeoob = false;
static bool   autoplace = false;
static bool   uboot = false;
static bool   markbad = false;
static bool   forcejffs2 = false;
static bool   forceyaffs = false;
static bool   forcelegacy = false;
static bool   noecc = false;
static bool   pad = false;
static int   blockalign = 1; /*default to using 16K block size */

static void process_options (int argc, char * const argv[])
{
int error = 0;

for (;;) {
   int option_index = 0;
   static const char *short_options = "ab:fjmnopqs:uy";
   static const struct option long_options[] = {
    {"help", no_argument, 0, 0},
    {"version", no_argument, 0, 0},
    {"autoplace", no_argument, 0, ‘a’},
    {"blockalign", required_argument, 0, ‘b’},
    {"forcelegacy", no_argument, 0, ‘f’},
    {"jffs2", no_argument, 0, ‘j’},
    {"markbad", no_argument, 0, ‘m’},
    {"noecc", no_argument, 0, ‘n’},
    {"oob", no_argument, 0, ‘o’},
    {"pad", no_argument, 0, ‘p’},
    {"quiet", no_argument, 0, ‘q’},
    {"start", required_argument, 0, ‘s’},
    {"uboot", no_argument, 0, ‘u’},
    {"yaffs", no_argument, 0, ‘y’},
    {0, 0, 0, 0},
   };

   int c = getopt_long(argc, argv, short_options,
     long_options, &option_index);
   if (c == EOF) {
    break;
   }

   switch (c) {
    case 0:
     switch (option_index) {
      case 0:
       display_help();
       break;
      case 1:
       display_version();
       break;
     }
     break;
    case ‘q’:
     quiet = true;
     break;
    case ‘a’:
     autoplace = true;
     break;
    case ‘u’:
     uboot = true;
     break;
    case ‘j’:
     forcejffs2 = true;
     break;
    case ‘y’:
     forceyaffs = true;
     break;
    case ‘f’:
     forcelegacy = true;
     break;
    case ‘n’:
     noecc = true;
     break;
    case ‘m’:
     markbad = true;
     break;
    case ‘o’:
     writeoob = true;
     break;
    case ‘p’:
     pad = true;
     break;
    case ‘s’:
     mtdoffset = strtol (optarg, NULL, 0);
     break;
    case ‘b’:
     blockalign = atoi (optarg);
     break;
    case ‘?’:
     error++;
     break;
   }
}

if (mtdoffset < 0) {
   fprintf(stderr, "Can’t specify a negative device offset `%d’n",
     mtdoffset);
   exit (EXIT_FAILURE);
}

argc -= optind;
argv += optind;

/*
* There must be at least the MTD device node positional
* argument remaining and, optionally, the input file.
*/

if (argc < 1 || argc > 2 || error)
   display_help ();

mtd_device = argv[0];

/*
* Standard input may be specified either explictly as "-" or
* implicity by simply omitting the second of the two
* positional arguments.
*/

img = ((argc == 2) ? argv[1] : standard_input);
}

int main(int argc, char * const argv[])
{

process_options(argc, argv);

}

其中,上面那个uboot命令,我是照葫芦画瓢,自己添加的。

【注意】

在添加uboot参数支持的时候,无意间,犯了个错误,把

   static const char *short_options = "ab:fjmnopqs:uy";
写成了

   static const char *short_options = "ab:fjmnopqsu:y";
把u字符放在了s和冒号中间,导致

    case ‘s’:
     mtdoffset = strtol (optarg, NULL, 0);
     break;
中去调用strtol,出现Segmentation fault,查到最后,发现是上面u字母防错位置导致传入给strol的optarg是NULL,所以才出现Segmentation fault。

因此,要注意的就是,在添加参数支持的时候,当某个选项是需要参数的时候,比如

   static const char *short_options = "ab:fjmnopqs:uy";
。。。

    {"start", required_argument, 0, ‘s’},

。。。

    case ‘s’:
     mtdoffset = strtol (optarg, NULL, 0);
     break;
上面   static const char *short_options = "ab:fjmnopqs:uy";
中的冒号“:”表示是参数的意思,s和冒号之间不能分开了,否则就误以为后面的选项是s的参数了。

【引用】

1.getopt()与getopt_long()

http://edu.codepub.com/2009/0617/6513.php

2.linux 中解析命令行参数(getopt_long用法)

http://doc.chinaunix.net/linux/201003/456376.shtml

3.getopt与optarg

http://hi.baidu.com/snailzzz/blog/item/b0c95ee95ce2a435b90e2da3.html

转载请注明:在路上 » 【整理】getopt()或getopt_long()与optarg

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
80 queries in 0.161 seconds, using 22.11MB memory