我记不住的getopt_long的那些参数和返回值

前言:最近在学习面向Linux系统进行C语言的编程,通过查询man手册和查看网络上的各种文章来获取一点点的知识,重点是看完手册还是一脸懵逼,搞不懂手册里面再说啥,而本篇文章将记录一下学习getopt_long的那些参数和返回值,希望能和大家讲清楚和说明白。

optstring分为三种选项 普通的,必须选项(:),可选选项(::),这个略,可以自行百度。

0. 可选选项

optstring 为 ":a::b:X"
Option syntaxMeaning
-a
OK, No argument provided (optional).
-afoo
OK, argument is foo
-a foo
Wrong, no space allowed with optional arguments.
foo is considered a non-option argument.
-bfoo
OK, argument is foo (required).
-b foo
OK, argument is foo (required).
-b
Wrong, option b requires an argument.

注意:可选参数需要紧紧挨着写,不能有空格。

1. 未知的选项和缺少选项参数(Unknown Options and Missing Option Arguments)

当我们面对上面两个情况时候,如何进行处理

optstring为 "a:b:X"

当我们输入 -t 时候会出现 "未知的选项"的错误;

当我们输入 -a 而不输入选项参数时候,会出现"缺少选项参数"的错误;

一般情况下getopt会输出错误,但是我们希望我们能有相关的语句去处理或自定义提示。

我们通过在 optstring前面添加 ":",即 ":a:b:X"来进行解决,代码如下所示:

/* Notice the leading : in the option string */   

opt

while ((opt = getopt(argc, argv, ":a:b:X")) != -1) 
{
   switch (opt) 
   {
    case 'a':
      printf("Option a has arg: %s\n", optarg);
      break;
    case 'b':
      printf("Option b has arg: %s\n", optarg);
      break;
    case 'X':
      printf("Option X was provided\n");
      break;
    case '?':
      printf("Unknown option: %c\n", optopt);
      break;
    case ':':
      printf("Missing arg for %c\n", optopt);
      break;
   }
}

假设这个程序输出为a.out, 则测试结果为:

Command line optionsOutput
./a.out -a
Missing arg for a
./a.out -t
Unknown option: t
./a.out -a one -t -X -b
Option a has arg: one
Unknown option: t
Option X was provided
Missing arg for b
./a.out -a one,two,three
Option a has arg: one,two,three
./a.out -a "one two three"
Option a has arg: one two three

我们查看文档, man 3 getopt 有如下文字,与咱们测试结果一致:

是说以":"开头的话,getopt不会打印错误同时针对 缺少选项参数的情况会返回 ":" ,这样可以让调用者或开发者区分这两种情况。通过添加":"将getopt关闭打印错误输出。

2. nonoption是否有序及获取相关值

nonoption,换一种写法 non-option也行,意思是非选项参数

比如,我们执行gcc程序,如下所示:

gcc -Wall -Wextra main.c foo.c bar.c -O -o program -ansi -pedantic -Werror

哪个是non-option,其实就是前面没有"-"和"--"的,也就是 main.c/foo.c/bar.c, 而 program是-o选项的参数它不是nonoption。

我们先试一下:

#include <stdio.h>  /* printf */
#include <getopt.h> /* getopt */

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

  while ((opt = getopt(argc, argv, ":a:b:X")) != -1) 
  {
     switch (opt) 
     {
      case 'a':
        printf("Option a has arg: %s\n", optarg);
        break;
      case 'b':
        printf("Option b has arg: %s\n", optarg);
        break;
      case 'X':
        printf("Option X was provided\n");
        break;
      case '?':
        printf("Unknown option: %c\n", optopt);
        break;
      case ':':
        printf("Missing arg for %c\n", optopt);
        break;
     }
  }

    /* Get all of the non-option arguments */
  if (optind < argc) 
  {
    printf("Non-option args: ");
    while (optind < argc)
      printf("%s ", argv[optind++]);
    printf("\n");
  }
  
  return 0;
}

测试结果为:

Command line optionsOutput
./a.out x -a one y -X z
Option a has arg: one
Option X was provided
Non-option args: x y z 
./a.out x y z -a one -b two
Option a has arg: one
Option b has arg: two
Non-option args: x y z 

我们发现了一个奇怪的现象,就是这些非选项参数即使写在了其他选项参数的前面,但是它输出在了最后面,也就是说并没有按照书写的顺序进行输出。

原因是:getopt函数会将这些非选项参数放到数组argv的最后,当没有选项处理则返回-1并终止while循环。我们通过optind进行循环来获取后续的参数。

如果你想获取这些 非选项参数并且是按顺序进行输出,你需要在optstring前加"-",通过添加"-"来关闭getopt将non option移动到argv数组末尾。

#include <stdio.h>  /* printf */
#include <getopt.h> /* getopt */

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

     /* Notice the leading minus sign - in the option string below   */   
     /* Remember that the number one in single quotes '1' is not the */   
     /* same as the number one without quotes. '1' is ASCII 49       */   
  while ((opt = getopt(argc, argv, "-:a:b:X")) != -1) 
  {
     switch (opt) 
     {
      case 'a':
        printf("Option a has arg: %s\n", optarg);
        break;
      case 'b':
        printf("Option b has arg: %s\n", optarg);
        break;
      case 'X':
        printf("Option X was provided\n");
        break;
      case '?':
        printf("Unknown option: %c\n", optopt);
        break;
      case ':':
        printf("Missing arg for %c\n", optopt);
        break;
      case 1:
        printf("Non-option arg: %s\n", optarg);
        break;
     }
  }
  
  return 0;
}

当存在 non option出现时候,getopt_long函数返回值为 1

测试结果为:

Command line optionsOutput
./a.out x y z -a foo

Non-option arg: x

Non-option arg: y

Non-option arg: z

Option a has arg: foo

./a.out x -a foo y -b bar z -X w

Non-option arg: x

Option a has arg: foo

Non-option arg: y

Option b has arg: bar

Non-option arg: z

Option X was provided

Non-option arg: w

./a.out -t x -a foo -M y -b bar z -X w -b
Unknown option: t
Non-option arg: x
Option a has arg: foo
Unknown option: M
Non-option arg: y
Option b has arg: bar
Non-option arg: z
Option X was provided
Non-option arg: w
Missing arg for b

3.长选项以及短选项和长选项的关联

短选项的缺点是:

1. 选项个数受限,对于小程序这个倒没事,但是对于一个复杂的程序就显着不足,

2. 无法记住短选项的意思,比如 -a代表add,但是无法代表alter等

看一下rsync和wget你就会发现有很多的参数,而 getopt_long就是处理长选项的函数。

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

argc 代表参数的个数

argv 代表保存各个参数的数组,每个参数是一个字符串

optstring 代表短选项的字符串

longopts 代表长选项的配置数组指针

longindex 代表 longopts数组的索引的指针

struct option 
{
  const char *name;    /* name without -- in front                                  */
  int         has_arg; /* one of: no_argument, required_argument, optional_argument */
  int        *flag;    /* how the results are returned                              */
  int         val;     /* the value to return or to put in flag                     */
};


static struct option long_options[] = 
      {
          {"add",     required_argument, NULL,  0 },
          {"append",  no_argument,       NULL,  0 },
          {"delete",  required_argument, NULL,  0 },
          {"verbose", no_argument,       NULL,  0 },
          {"create",  required_argument, NULL,  0 },
          {"file",    optional_argument, NULL,  0 },
          {NULL,      0,                 NULL,  0 }
      };

如果flag为NULL,则这个 getopt_long函数返回 val 

如果flag为指针,则将val放到flag指针中,这个getopt_long函数返回 0 

测试程序如下:

#include <getopt.h> /* getopt */
#include <stdlib.h> /* exit   */
#include <stdio.h>  /* printf */

int main(int argc, char **argv)
{
  int c;
  while (1) {
    int option_index = 0;
    static struct option long_options[] = 
    {
        {"add",     required_argument, NULL,  'a'},
        {"append",  no_argument,       NULL,  'p'},
        {"delete",  required_argument, NULL,  'd'},
        {"verbose", no_argument,       NULL,  'v'},
        {"create",  required_argument, NULL,  'c'},
        {"file",    optional_argument, NULL,  'f'},
        {NULL,      0,                 NULL,    0}
    };

      /* Still need to provide an option string for the short options */
    c = getopt_long(argc, argv, "-:a:pd:vc:f::", long_options, &option_index);
    if (c == -1)
      break;

    switch (c) 
    {
      case 0:
        printf("long option %s", long_options[option_index].name);
        if (optarg)
           printf(" with arg %s", optarg);
        printf("\n");
        break;

      case 1:
        printf("regular argument '%s'\n", optarg);
        break;

      case 'a':
        printf("option a with value '%s'\n", optarg);
        break;

     case 'p':
        printf("option p\n");
        break;

      case 'd':
        printf("option d with value '%s'\n", optarg);
        break;

     case 'v':
        printf("option v\n");
        break;

      case 'c':
        printf("option c with value '%s'\n", optarg);
        break;

      case 'f':
        printf("option f with value '%s'\n", optarg ? optarg : "NULL");
        break;

      case '?':
        printf("Unknown option %c\n", optopt);
        break;

      case ':':
        printf("Missing option for %c\n", optopt);
        break;

      default:
        printf("?? getopt returned character code %c ??\n", c);
     }
}

测试结果为:

Command lineOutput
./a.out --delete=foo -c5 --add=yes --append
option d with value 'foo'
option c with value '5'
option a with value 'yes'
option p
./a.out --d=foo --ad=yes --ap
option d with value 'foo'
option a with value 'yes'
option p
./a.out --create=5 --create 6 --c=7 --c 8  
option c with value '5'
option c with value '6'
option c with value '7'
option c with value '8'
./a.out --file=5 --file 6 --file7
option f with value '5'
option f with value 'NULL'
regular argument '6'
Unknown option 

--d能匹配上--delete,--ad能匹配上--add,--ap能匹配上--append,--c能匹配上--create

4. 传true或false

有些时候的选项并不进行传值,而是传true或false

gcc -c foo.c   // -c 就是一个flag,代表true只编译不链接。如果不写,则进行编译和链接。
#include <getopt.h> /* getopt */
#include <stdio.h>  /* printf */

/* File scope flags, all default to 0 */
static int f_add;
static int f_append;
static int f_create;
static int f_delete;
static int f_verbose;

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

  while (1) 
  {
    int option_index = 0;
    static struct option long_options[] = 
    {
      {"add",     no_argument, &f_add,     1},
      {"append",  no_argument, &f_append,  1},
      {"create",  no_argument, &f_create,  1},
      {"delete",  no_argument, &f_delete,  1},
      {"verbose", no_argument, &f_verbose, 1},
      {NULL,      0,           NULL,       0}
    };

    c = getopt_long(argc, argv, "-:", long_options, &option_index);
    printf("the value of c : %d\n",c);
    if (c == -1)
      break;

    switch (c) 
    {
      case 1:
        printf("non option argument '%s'\n", optarg);
        break;

      case '?':
        printf("Unknown option %c\n", optopt);
        break;
    }
  }

  printf("    f_add: %i\n", f_add);
  printf(" f_append: %i\n", f_append);
  printf(" f_delete: %i\n", f_delete);
  printf(" f_create: %i\n", f_create);
  printf("f_verbose: %i\n", f_verbose);

  return 0;
}

测试结果为:

 

Command lineOutput
./a.out --verbose --create
    f_add: 0
 f_append: 0
 f_delete: 0
 f_create: 1
f_verbose: 1
./a.out --verbose --append --create --add --delete
    f_add: 1
 f_append: 1
 f_delete: 1
 f_create: 1
f_verbose: 1
./a.out --v --c --ap --ad --d
    f_add: 1
 f_append: 1
 f_delete: 1
 f_create: 1
f_verbose: 1
./a.out -v -c -d -a
Unknown option v
Unknown option c
Unknown option d
Unknown option a
    f_add: 0
 f_append: 0
 f_delete: 0
 f_create: 0
f_verbose: 0

如果flag为NULL,则这个 getopt_long函数返回 val 

如果flag为指针,则将val放到flag指针中,这个getopt_long函数返回 0 

5. 我的小代码

#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit */
#include <getopt.h>

int main(int argc, char *argv[])
{
	int c;
	int digit_optind = 0;

	// 默认为0
        static int f_flag;
	while (1) {
		int this_option_optind = optind ? optind : 1;
		int option_index = 0;
		static struct option long_options[] = {
			{"add",     required_argument, 0, 'a'},
			{"append",  no_argument,       0, 'p'},
			{"delete",  required_argument, 0, 'd'},
			{"verbose", no_argument,       0, 'v'},
			{"create",  required_argument, 0, 'c'},
			{"file",    optional_argument, 0, 'f'},
			{"help",    no_argument,       0, 'h'},
			{"flag",    no_argument, &f_flag,  1 },
			{0,         0,                 0,  0 }
		};

		c = getopt_long(argc, argv, "-:a:pd:vc:f::h",long_options, &option_index);
		//printf("the value of c : %d\n",c)
		if (c == -1)
			break;

		switch (c) 
		{
			case 0:
				printf("%s (true of false),the flag value is %d\n", long_options[option_index].name,f_flag);
				break;

			case 1:
				printf("non option argument '%s'\n", optarg);
				break;

			case 'a':
				printf("option a or add with value '%s'\n", optarg);
				break;

			case 'p':
				printf("option p or append\n");
				break;

			case 'd':
				printf("option d or delete with value '%s'\n", optarg);
				break;

			case 'v':
				printf("option v or verbose\n");
				break;

			case 'c':
				printf("option c or create with value '%s'\n", optarg);
				break;

			case 'f':
				printf("option f or file with value '%s'\n", optarg ? optarg : "NULL");
				break;

			case '?':
				printf("Unknown option %c\n", optopt);
				break;

			case ':':
				printf("Missing option for %c\n", optopt);
				break;

			default:	
				printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
				printf("\t-a,--add           add somethings(required argument)\n");
				printf("\t-p,--append        append somethings(no argument)\n");
				printf("\t-d,--delete        delete somethings(required argument)\n");
				printf("\t-v,--verbose       show the verbose(no argument)\n");
				printf("\t-c,--create        create somethings(required argument)\n");
				printf("\t-f,--file          add a file(required argument)\n");
				printf("\t-h,--help          help(no argument)\n");
				printf("\t--flag             flag 0 or 1(no argument)\n");
				printf("\n");
				exit(0);
		}
	} 
	exit(EXIT_SUCCESS);
}

这个代码可以输出帮助信息,以及 上述0、1、2、3、4等各种问题的结合版,可以参考,谢谢。

参考文档:

1. Example of Getopt (The GNU C Library)

2. man 3 getopt

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/155312.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA无法查看源码是.class,而不是.java解决方案?

问题&#xff1a;在idea中&#xff0c;ctrl鼠标左键进入源码&#xff0c;但是有时候会出现无法查看反编译的源码&#xff0c;如图&#xff01; 而我们需要的是方法1: mvn dependency:resolve -Dclassifiersources 注意&#xff1a;需要该模块的目录下&#xff0c;不是该文件目…

计算机毕业设计选题推荐-幼儿园管理微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

LeetCode(24)文本左右对齐【数组/字符串】【困难】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 文本左右对齐 1.题目 给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单…

spring中的DI

【知识要点】 控制反转&#xff08;IOC&#xff09;将对象的创建权限交给第三方模块完成&#xff0c;第三方模块需要将创建好的对象&#xff0c;以某种合适的方式交给引用对象去使用&#xff0c;这个过程称为依赖注入&#xff08;DI&#xff09;。如&#xff1a;A对象如果需要…

flutter web 中嵌入一个html

介绍 flutter web 支持使用 HtmlElementView嵌入html import dart:html; import dart:ui as ui; import package:flutter/cupertino.dart;class WebWidget extends StatelessWidget {const WebWidget({super.key});overrideWidget build(BuildContext context) {DivElement fr…

flutter绘制弧形进度条

绘制&#xff1a; import package:jade/utils/JadeColors.dart; import package:flutter/material.dart; import dart:math as math; import package:flutter_screenutil/flutter_screenutil.dart;class ArcProgressBar extends StatefulWidget{const ArcProgressBar({Key key…

Linux系统进程——进程的退出、子进程退出的收集、孤儿进程

进程退出 进程退出主要分为两种&#xff1a;正常退出、异常退出 正常退出 正常退出分为以下几种&#xff1a; 1.main函数调用return 2.进程调用exit(),标准c库 3.进程调用 _exit() 或者 _Exit() &#xff0c;属于系统调用 4.进程最后一个线程返回 5.最后一个线程调用pthrea…

晨控CK-FR08读卡器与汇川PLC连接EtherCAT通讯手册

晨控CK-FR08读卡器与汇川PLC连接EtherCAT通讯手册 晨控CK-FR08系列是一款基于射频识别技术的高频RFID标签读卡器&#xff0c;读卡器工作频率为13.56MHZ&#xff0c;支持对I-CODE 2、I-CODE SLI等符合ISO15693国际标准协议格式标签的读取。 读卡器同时支持标准工业通讯协议Eth…

ubuntu20源码编译搭建SRS流媒体服务器

第一、下载源码 下载源码&#xff0c;推荐用Ubuntu20&#xff1a; git clone -b develop https://gitee.com/ossrs/srs.git第二、编译 2.1、切换到srs/trunk目录&#xff1a; cd srs/trunk2.2、执行configure脚本 ./configure2.3、执行make命令 make2.4、修改conf/rtmp.c…

通讯录实现之进阶版将通讯录数据保存在文件中(完整代码)

我们在之前的博客中已经写过两版通讯录了&#xff1a; 第一版是用C语言实现了通讯录&#xff0c;但是通讯录的存储人数信息是固定的&#xff0c;用完就没有了 感兴趣的可以转到对应博客看一下&#xff0c;附带链接&#xff1a;第一版通讯录 第二版是在第一版的基础上动态开辟…

从零开始 通义千问大模型本地化到阿里云通义千问API调用

从零开始 通义千问大模型本地化到阿里云通义千问API调用 一、通义千问大模型介绍 何为“通义千问”&#xff1f; “通义千问大模型”是阿里云推出的一个超大规模的语言模型&#xff0c;具有强大的归纳和理解能力&#xff0c;可以处理各种自然语言处理任务&#xff0c;包括但…

DAC实验(DAC 输出三角波实验)(DAC 输出正弦波实验)

DAC 输出三角波实验 本实验我们来学习使用如何让 DAC 输出三角波&#xff0c;DAC 初始化部分还是用 DAC 输出实验 的&#xff0c;所以做本实验的前提是先学习 DAC 输出实验。 使用 DAC 输出三角波&#xff0c;通过 KEY0/KEY1 两个按键&#xff0c;控制 DAC1 的通道 1 输出两种…

文旅媒体有哪些?如何邀请到现场报道?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 中国文旅产业在近年来得到了持续而快速的发展。从产业端看&#xff0c;中国文旅产业呈现出新的发展趋势&#xff0c;其中“文旅”向“文旅”转变成为显著特点。通过产业升级和空间构建&a…

Shell编程基础(3)- Shell的位置参数

Shell编程基础&#xff08;3&#xff09;- Shell的位置参数 Shell Scripting Essentials (3) – Locative Parameters of Shell Scripting 前文介绍过shell变量。当声明shell变量时&#xff0c;只需要在代码行写出变量名称即可;在输入行用read命令要求用户输入&#xff0c;在…

Day48 力扣动态规划 : 647. 回文子串 |516.最长回文子序列 |动态规划总结篇

Day48 力扣动态规划 : 647. 回文子串 &#xff5c;516.最长回文子序列 &#xff5c;动态规划总结篇 647. 回文子串第一印象看完题解的思路dp递推公式初始化递归顺序 实现中的困难感悟代码 516.最长回文子序列第一印象我的尝试遇到的问题 看完题解的思路dp递推公式初始化 实现中…

设计基于STM32F103C8T6微控制器的巡线小车

巡线小车是一种能够在一条预定线追踪路径的小车&#xff0c;广泛应用于工业自动化、物流仓储、智能家居等领域。本设计将使用STM32F103C8T6微控制器来实现一个基础的巡线小车。 硬件组成&#xff1a;1. STM32F103C8T6微控制器开发板&#xff1a;作为巡线小车的核心控制器&…

双剑合璧:基于Elasticsearch的两路召回语义检索系统,实现关键字与语义的高效精准匹配

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

NewStarCTF2023 Reverse Week3 EzDLL WP

分析 这里调用了z3h.dll中的encrypt函数。 用ida64载入z3h.dll 直接搜索encrypt 找到了一个XTEA加密。接着回去找key和密文。 发现key 这里用了个调试状态来判断是否正确&#xff0c;v71&#xff0c;要v7&#xff1d;1才会输出Right&#xff0c;即程序要处于飞调试状态。 可…

asp.net core EF Sqlserver

一、EF CORE的使用 1、使用NuGet来安装EF CORE 使用程序包管理器控制台&#xff0c;进行命令安装 //安装 Microsoft.EntityFrameworkCoreInstall-Package Microsoft.EntityFrameworkCore //安装 Microsoft.EntityFrameworkCore.SqlServer Install-Package Microsoft.EntityF…

Java智慧工地云SaaS源码,AI服务器、智能硬件

智慧工地智能硬件 一、自动喷淋控制 当扬尘监测值超过在智慧工地系统中设定的闽值后自动喷淋控制系统通过接收系统发出的开关指令&#xff0c;实现自动、及时喷淋降尘&#xff0c;同时系统可设置自动喷淋时间段&#xff0c;每天定时喷淋&#xff0c;避免环境污染。 二、智能电…