命令行参数解析的两种方法

前言

    在实际工程使用中,命令行参数解析主要用于灵活的使用demo或库中不同功能特性,是一个非常重要的功能。本文主要讲述两种命令行参数解析的方法,重要讲述Linux平台采用getopt函数的方法进行命令行参数解析。在Linux系统中,Linux命令用法的参数解析一般采用getopt()或getopt_long()的方法进行,这种方法可以任意指定参数,不需要按顺序指定,更加灵活。

1、参考

Parsing program options using getopt
getopt函数和getopt_long函数详解
浅谈linux的命令行解析参数之getopt_long函数

2、命令行参数解析的两种方法

2.1 普通的命令行参数解析方法

具体参见:
【PE/C系列】C工程中灵活的参数解析方式

主要是通过字符串函数strcmp和strncmp进行参数的解析。

if(argc > 1)
{
   int i = 0;
   for(i = 1; i < argc; ++i)
   {
      if(!strncmp(argv[i], "-h", 2) || !strncmp(argv[i], "-help", 5))
      {
          print_help(argv[0]);
      }
      else if(!strncmp(argv[i], "-s", 2))
      {
          width = atoi(argv[++i]);
          height = atoi(argv[++i]);
      }
      else if(!strcmp(argv[i], "-ss", 3))
      {
          length = atoi(argv[++i]);
      }
   }
}

2.2 通过getopt函数进行命令行参数解析(仅限Linux平台)

2.2.1 getopt和getopt_long函数用法

函数声明:

#include<unistd.h>
#include<getopt.h>          /*所在头文件 */
/*函数声明*/
int getopt(intargc, char * const argv[], const char *optstring);
int getopt_long(int argc, char * const argv[], const char *optstring,
                          const struct option *longopts, int*longindex);
int getopt_long_only(int argc, char * const argv[],const char *optstring,
                          const struct option *longopts, int*longindex);
 /*系统声明的全局变量 */
extern char *optarg;        
extern int optind, opterr, optopt;

全局变量的作用:

  • Variable: int opterr
    参数opterr不等于0,在参数解析时遇到未知选项或者缺少必要参数时,会打印错误信息给标准错误流。
    参数opterrr等于0,不会打印任何信息,但是仍然返回?表示错误信息。
    If the value of this variable is nonzero, then getopt prints an error message to the standard error stream if it encounters an unknown option character or an option with a missing required argument. This is the default behavior. If you set this variable to zero, getopt does not print any messages, but it still returns the character ? to indicate an error.
  • Variable: int optopt 表示最后一个未知选项。
    When getopt encounters an unknown option character or an option with a missing required argument, it stores that option character in this variable. You can use this for providing your own diagnostic messages.

  • Variable: int optind 表示argv数组中下一个元素的索引。
    This variable is set by getopt to the index of the next element of the argv array to be processed. Once getopt has found all of the option arguments, you can use this variable to determine where the remaining non-option arguments begin. The initial value of this variable is 1.

  • Variable: char * optarg 表示指向当前选项参数的指针。
    This variable is set by getopt to point at the value of the option argument, for those options that accept arguments.

getopt函数用法:只支持短选项 -a

具体参考:Using-Getopt

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

getopt函数用于从argc和argv[]指定的参数列表中获取下一个选项参数。

参数optstring: 比如getopt(argc, argv, “td:ch:q::”)

  1. 单个字符,表示选项,这里一共有t、d、c、h、q五个选项;
  2. 单个字符后接一个冒号“:”表示该选项后必须跟一个参数,参数紧跟在选项后或者以空格隔开;
  3. 单个字符后跟两个冒号,表示该选项后可以跟一个参数,也可以不跟,如果后边跟一个参数,参数必须紧跟在选项后不能以空格隔开。

返回值:
The getopt function returns the option character for the next command line option. When no more option arguments are available, it returns -1.

getopt_long函数用法:支持短选项和长选项--all

具体参考:Getopt-Long-Options

#include<getopt.h>          /*所在头文件 */
int getopt_long(int argc, char * const argv[], const char *optstring,
                          const struct option *longopts, int*longindex);
  • 参数optstring表示短选项参数;
  • 参数longopts表示长选项参数;
  • 参数longindex表示选项索引(即longopts的下标值)。

举个栗子:

struct option
{  
     const char *name;     //表示选项的名称
     int         has_arg;  //表示选项后面是否携带参数。该参数有三个不同值:
     //no_argument(或者是0);required_argument(或者是1);optional_argument(或者是2)
     int        *flag;   // 空或者非空。
      //a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。
      // b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。
     int         val;   //表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val
};  
eg:
 static struct option longOpts[] = {
      { "daemon", no_argument, NULL, 'D' },
      { "dir", required_argument, NULL, 'd' },
      { "out", required_argument, NULL, 'o' },
      { "log", required_argument, NULL, 'l' },
      { "split", required_argument, NULL, 's' },
      { "http-proxy", required_argument, &lopt, 1 },
      { "http-user", required_argument, &lopt, 2 },
      { "http-passwd", required_argument, &lopt, 3 },
      { "http-proxy-user", required_argument, &lopt, 4 },
      { "http-proxy-passwd", required_argument, &lopt, 5 },
      { "http-auth-scheme", required_argument, &lopt, 6 },
      { "version", no_argument, NULL, 'v' },
      { "help", no_argument, NULL, 'h' },
      { 0, 0, 0, 0 }
    };

getopt_long_only函数用法:只支持长选项--all

#include<getopt.h>          /*所在头文件 */
int getopt_long_only(int argc, char * const argv[],const char *optstring,
                          const struct option *longopts, int*longindex);

2.2.2 实例用法Demo

参考:
Example-of-Getopt
Getopt-Long-Option-Example

1、GNUC Linux提供的Demo:

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

int main (int argc, char **argv)
{
  int aflag = 0;
  int bflag = 0;
  char *cvalue = NULL;
  int index;
  int c;

  opterr = 0;

  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 ();
      }

  printf ("aflag = %d, bflag = %d, cvalue = %s\n",
          aflag, bflag, cvalue);

  for (index = optind; index < argc; index++)
    printf ("Non-option argument %s\n", argv[index]);
  return 0;
}

2、实例Demo:

static const char *short_options = "ABCDEb:c:d:f:I:i:L:M:m:n:r:s:T:t:vy:";
/*!
 * @brief `-A --streamA` : Specify the following options are for stream A
 */
#define STREAM_A_OPTION \
    {"streamA",    NO_ARG,        0,    'A'},

/*!
 * @brief `-B --streamB` : Specify the following options are for stream B
 */
#define STREAM_B_OPTION \
    {"streamB",    NO_ARG,     0,    'B'},

/*!
 * @brief `-C --streamC` : Specify the following options are for stream C
 */
#define STREAM_C_OPTION \
    {"streamC",    NO_ARG,        0,    'C'},

/*!
 * @brief `-D --streamD` : Specify the following options are for stream D
 */
#define STREAM_D_OPTION \
    {"streamD",    NO_ARG,        0,    'D'},

/*!
 * @brief `-E --streamE` : Specify the following options are for stream E
 */
#define STREAM_E_OPTION \
    {"streamE",    NO_ARG,        0,    'E'},

/*!
 * @brief `-t --type` : Specify the supported EFM type, 0: YUV File, 1: YUV Capture, 2: YUV RAW, 3: RGB RAW
 */
#define TYPE_OPTION \
    {"type",    HAS_ARG,    0,    't'},

/*!
 * @brief `-b --buffer` : Specify the source buffer for YUV Capture
 */
#define BUFFER_OPTION \
    {"buffer",    HAS_ARG,    0,    'b'},

/*!
 * @brief `-f --yuv-format` : Specify YUV format of the YUV input file for YUV File
 */
#define YUV_FORMAT_OPTION \
    {"yuv-format",    HAS_ARG,    0,    'f'},

/*!
 * @brief `-y --yuv-input` : Specify YUV input file path for YUV File, if multi input files, please
 * input prefix, like xxx_0.yuv, xxx_1.yuv, please input xxx
 */
#define YUV_INPUT_OPTION \
    {"yuv-input",    HAS_ARG,    0,    'y'},

/*!
 * @brief `-i --raw-input` : pecify raw input (RGB or YUV) file path, if multi input files, please
 * input prefix, like xxx_0.raw, xxx_1.raw, please input xxx
 */
#define RAW_INPUT_OPTION \
    {"raw-input",    HAS_ARG,    0,    'i'},

/*!
 * @brief `-m --me1-input` : Specify ME1 input file path for YUV File, if multi input files, please
 * input prefix, like xxx_0.me1, xxx_1.me1, please input xxx
 */
#define ME1_INPUT_OPTION \
    {"me1-input",    HAS_ARG,    0,    'm'},

/*!
 * @brief `-M --me0-input` : Specify ME0 input file path for YUV File, if multi input files, please
 * input prefix, like xxx_0.me0, xxx_1.me0, please input xxx
 */
#define ME0_INPUT_OPTION \
    {"me0-input",    HAS_ARG,    0,    'M'},

/*!
 * @brief `-n --frame-num` [>0]: Specify frame number to be encoded
 */
#define FRAME_NUM_OPTION \
    {"frame-num",    HAS_ARG,    0,    'n'},

/*!
 * @brief `-s --frame-size` [resulotion]: Specify the frame resolution for YUV/RAW file
 */
#define FRAME_SIZE_OPTION \
    {"frame-size",    HAS_ARG,    0,    's'},

/*!
 * @brief `-r --frame-rate` : Specify the frame rate of YUV input file for YUV File
 */
#define FRAME_RATE_OPTION \
    {"frame-rate",    HAS_ARG,    0,    'r'},

/*!
 * @brief `-I --file-index` [m~n]: Specify the input file index
 */
#define FILE_INDEX_OPTION \
    {"file-index",    HAS_ARG,    0,    'I'},

/*!
 * @brief `-L --loop-num` [>0]: Specify the loop num
 */
#define LOOP_NUM_OPTION \
    {"loop-num",    HAS_ARG,    0,    'L'},

/*!
 * @brief `-c --copy-method` [0|1]: Specify the copy method for YUV Capture, 0: GDMA, 1: ARM
 */
#define COPY_METHOD_OPTION \
    {"copy-method",    HAS_ARG,    0,    'c'},

/*!
 * @brief `-T --feed-type` [0|1]: Specify the YUV feed type for YUV File, 0: Normal, 1: Repeate
 */
#define FEED_TYPE_OPTION \
    {"feed-type",    HAS_ARG,    0,    'T'},

/*!
 * @brief `-d --me-method` [0|1]: Specify the method of me downscale, 0: Normal, 1: Neon, default 0
 */
#define ME_METHOD_OPTION \
    {"me-method",    HAS_ARG,    0,    'd'},

/*!
 * @brief `-v --verbose` : Print more information
 */
#define VERBOSE_OPTION \
    {"verbose",    NO_ARG,    0,    'v'},

/*! @} */

static struct option long_options[] = {
    STREAM_A_OPTION
    STREAM_B_OPTION
    STREAM_C_OPTION
    STREAM_D_OPTION
    STREAM_E_OPTION
    TYPE_OPTION
    BUFFER_OPTION
    YUV_FORMAT_OPTION
    YUV_INPUT_OPTION
    RAW_INPUT_OPTION
    ME1_INPUT_OPTION
    ME0_INPUT_OPTION
    FRAME_NUM_OPTION
    FRAME_SIZE_OPTION
    FRAME_RATE_OPTION
    FILE_INDEX_OPTION
    LOOP_NUM_OPTION
    COPY_METHOD_OPTION
    FEED_TYPE_OPTION
    ME_METHOD_OPTION
    VERBOSE_OPTION
    {0,    0,    0,    0},
};
int init_param(int argc, char **argv)
{
    int ch, value;
    int width, height;
    int option_index = 0;
    u32 min_value, max_value;

    opterr = 0;
    while ((ch = getopt_long(argc, argv, short_options, long_options,
        &option_index)) != -1) {
        switch (ch) {
        case 'A':
            current_stream = 0;
            break;
        case 'B':
            current_stream = 1;
            break;
        case 'C':
            current_stream = 2;
            break;
        case 'D':
            current_stream = 3;
            break;
        case 'E':
            current_stream = 4;
            break;
        case 'f':
            value = atoi(optarg);
            yuv_format = value;
            break;
        case 'y':
            strcpy(yuv_name, optarg);
            break;
        case 'i':
            strcpy(raw_name, optarg);
            break;
        case 'm':
            strcpy(me1_name, optarg);
            break;
        case 'M':
            strcpy(me0_name, optarg);
            break;
        case 'n':
            value = atoi(optarg);
            frame_num = value;
            break;
        case 's':
            get_arbitrary_resolution(optarg, &width, &height);
            frame_size.width = width;
            frame_size.height = height;
            break;
        case 'r':
            frame_rate = atoi(optarg);
            break;
        case 'c':
            mem_cpy_type = atoi(optarg);
            break;
        case 'v':
            verbose = 1;
            break;
        default:
            printf("unknown option found: %c\n", ch);
            return -1;
        }
    }

    return 0;
}

THE END!


本博文只能阅读,谢绝转载,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2963033731@qq.com

文章标题:命令行参数解析的两种方法

字数:2.3k

本文作者:Soaring Lee

发布时间:2019-09-07, 15:13:47

最后更新:2021-08-13, 23:02:32

原始链接:https://soaringleefighting.github.io/2019/09/07/【PE系列】命令行参数解析的两种方法/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏

相册