C/C艹三分迷惘

命令行参数处理:getopt()和getopt_long()

2017-09-19  本文已影响0人  ChaseChoi

在实际编程当中,自己编写代码处理命令行参数是比较麻烦且易出错的。一般我们会直接使用getopt()getopt_long()函数,下文将介绍具体的使用方法。

getopt()

getopt()用于处理”单字母“选项,如-a, -t等。函数声明如下:

#include <unistd.h>                                              
int getopt(int argc, char *const argv[], const char *optstring);
   
extern char *optarg;
extern int optind, opterr, optopt;

参数说明

对于前两个参数argcgrgv[],一般直接使用main()传递进来的数值。用过C语言的同学应该比较熟悉,简单复习一下。

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char const *argv[])
{
    //在C99标准推出之前,变量不能在for()声明,为了兼容性,这里提前声明"i"
    int i;
    printf("argc = %d\n", argc);

    if (argc > 1)
    {
        for (i = 0; i < argc; ++i)
        {   
            printf("argv[%d] = %s\n", i, argv[i]);
        }
    }
    return 0;
}

argc: argument count, 记录了命令行参数的个数(包括命令本身)

argv: argument vector, 记录了命令行参数的具体内容

$ ./test 1 2 3
argc = 4 
argv[0] = ./test
argv[1] = 1
argv[2] = 2
argv[3] = 3

optstring: 作为getopt()的第三个参数,用于规定合法选项(option)以及选项是否带参数(argument)。一般为合法选项字母构成的字符串,如果字母后面带上冒号:就说明该选项必须有参数。如"ht:"说明有两个选项-h-t且后者(-t)必须带有参数(如-t 60)。

返回值

while ( (opt = getopt(argc, argv, "ab:") ) != -1) {...}
int oc;             /* option character */
char *b_opt_arg;

while ((oc = getopt(argc, argv, ":ab:")) != -1) {
    switch (oc) {
    case 'a':
        /* handle -a, set a flag, whatever */
        break;
    case 'b':
        /* handle -b, get arg value from optarg */
        b_opt_arg = optarg;
        break;
    case ':':
        /* missing option argument 参数缺失*/
        fprintf(stderr, "%s: option '-%c' requires an argument\n",
                argv[0], optopt);
        break;
    case '?':
    default:
        /* invalid option 非法选项*/
        fprintf(stderr, "%s: option '-%c' is invalid: ignored\n",
                argv[0], optopt);
        break;
    }
}

相关变量

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char optStr[] = "ab";
    int c;

    while ((c = getopt(argc, argv, optStr)) != -1) {
        printf("optind: %d\n", optind);
        switch (c) {
            case 'a':
                printf("-a\n"); 
                break;
            case 'b':
                printf("-b\n"); 
                break;
            case '?':
                printf("error\n");
                break;
          }
      }
    return 0;
}

测试结果:

$ ./a.out -ab  #例子1
optind: 1 
-a 
optind: 2
-b

$ ./a.out -a #例子2
optind: 2
-a

例子1:

#argv[]数据如下
argv[0]="./a.out"
argv[1]="-ab"
argv[2]=0

optind=1开始,处理完aoptind指向b所在位置,其实还是1;处理完b,指向下一个选项,即2

例子2:

#argv[]数据如下
argv[0]="./a.out"
argv[1]="-a"
argv[2]=0

optind=1开始,处理完a,指向下一个选项,即2

getopt_long()

根据函数名就可以知道getopt_long()用于处理长选项,如-help。函数声明如下:

#include <getopt.h>                                                
 
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex);

参数说明

前三个选项和getopt()完全相同,在此不再赘述。

struct option {
    const char *name;
    int has_arg;
    int *flag;
    int val;
};
  1. name: 长选项的名称
  2. has_arg: 参数情况
符号常量 数值 Meaning
no_argument 0 无参数
required_argument 1 有参数
optional_argument 2 参数可选

考虑到“可读性”,一般使用“符号常量”

  1. int *flag: 如果flagNULL, getup_long() 返回val的值; 如果不是NULL, val的值赋给flag指针指向的内容,同时getopt_long()返回 0
  2. int val: flagNULLval作为getopt_long()的返回值;如果flag不为NULLval赋值给flag指针所指内容;
int *flag return value
NULL val
&name(<— val) 0

通过例子(摘自webbench)可加深理解

static const struct option long_options[]=
{
   {"force",no_argument,&force,1}, //-force 参数三(flag)不为NULL,force=1,getopt_long()返回0
   {"reload",no_argument,&force_reload,1},
   {"time",required_argument,NULL,'t'},
   {"help",no_argument,NULL,'?'},  //-help 第三个参数(flag)为NULL,直接返回 "?"
   {"http09",no_argument,NULL,'9'},
   {"http10",no_argument,NULL,'1'},
   {"http11",no_argument,NULL,'2'},
   {"get",no_argument,&method,METHOD_GET},
   {"head",no_argument,&method,METHOD_HEAD},
   {"options",no_argument,&method,METHOD_OPTIONS},
   {"trace",no_argument,&method,METHOD_TRACE},
   {"version",no_argument,NULL,'V'},
   {"proxy",required_argument,NULL,'p'},
   {"clients",required_argument,NULL,'c'},
   {NULL,0,NULL,0} //最后一个元素应该全为0
};

int main(int argc, char *argv[])
{
  int options_index=0;
  ...
  while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
  {
    ...    
  }
}

注意: longopts数组最后一个元素应该全为0.

希望本文能帮助大家更好地理解getopt()getopt_long()。更多的相关用法可以参考Linux Programming by Example: The Fundamentals

上一篇下一篇

猜你喜欢

热点阅读