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

news2024/12/27 13:48:21

前言:最近在学习面向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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NFTScan 正式上线 Viction NFTScan 浏览器和 NFT API 数据服务

2023 年 11 月 16 号&#xff0c;NFTScan 团队正式对外发布了 Viction NFTScan 浏览器&#xff0c;将为 Viction 生态的 NFT 开发者和用户提供简洁高效的 NFT 数据搜索查询服务。NFTScan 作为全球领先的 NFT 数据基础设施服务商&#xff0c;Viction 是继 Bitcoin、Ethereum、BN…

GUI编程--PyQt5--QTreeWidget

文章目录 树型控件展示数据修改节点数据获取所有节点的数据 Qt模组参考 QWidgets QTreeWidget 树型控件展示数据 展示数据的同时&#xff0c;每个节点标注数据类型。 class MyWindow(QWidget):def __init__(self, title):super(MyWindow, self).__init__()self.setWindowTitl…

qt笔记之qml和C++的交互系列(一):初记

code review! —— 杭州 2023-11-16 夜 文章目录 一.qt笔记之qml和C的交互&#xff1a;官方文档阅读理解0.《Overview - QML and C Integration》中给出五种QML与C集成的方法1.Q_PROPERTY&#xff1a;将C类的成员变量暴露给QML2.Q_INVOKABLE()或public slots&#xff1a;将C类…

【面试经典150 | 数学】回文数

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;反转一半数字 其他语言python3 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本…

遵循开源软件安全路线图

毫无疑问&#xff0c;开源软件对于满足联邦任务所需的开发和创新至关重要&#xff0c;因此其安全性至关重要。 OSS&#xff08;运营支持系统&#xff09; 支持联邦政府内的每个关键基础设施部门。 联邦政府认识到这一点&#xff0c;并正在采取措施优先考虑 OSS 安全&#xff…

Android Jetpack的组件介绍,常见组件解析

jetpack组件有哪些 Android Jetpack是一个集成Android应用程序组件的一站式解决方案。它使开发人员能够专注于他们的应用程序的真正创新部分&#xff0c;而不会受到Android平台特定的限制。Jetpack组件可分为四个类别&#xff1a; 架构组件&#xff08;Architecture Componen…

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

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

STM32_SPI总线驱动OLED详细原理讲解

目录 这里写目录标题 第13章 Cortex-M4-SPI总线13.1 SPI总线概述13.1.1 SPI总线介绍13.1.2 SPI总线接口与物理拓扑结构13.1.3 SPI总线通信原理13.1.4 SPI总线数据格式 13.2 IO口模拟SPI操作OLED13.2.1 常见的显示设备13.2.2 OLED显示屏概述13.2.3 OLED特征13.2.4 显示原理13.2.…

stylelint报错at-rule-no-unknown

stylelint报错at-rule-no-unknown stylelint还将各种 sass -rules 标记mixin为include显示未知错误 at-rule-no-unknown ✖ stylelint --fix:Deprecation warnings: 78:1 ✖ Unexpected unknown at-rule "mixin" at-rule-no-unknown 112:3 ✖ Unexpected un…

第四章 串【24王道数据结构笔记】

1.串的基本概念 串&#xff0c;即字符串 (String) 是由零个或多个字符组成的有限序列。一般记为Sa1a2.....an(n>0) S"HelloWorld!" TiPhone 11 Pro Max? 其中&#xff0c;S是串名&#xff0c;单引号括起来的字符序列是串的值;a;可以是字母、数字或其他字符;串中…

DocCMS keyword SQL注入漏洞复现 [附POC]

文章目录 DocCMS keyword SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 DocCMS keyword SQL注入漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测…

idea中误删.iml和.idea文件,如何处理

目录 一、问题描述 二、解决方案 1、理论知识 &#xff08;1&#xff09;.iml 文件 &#xff08;2&#xff09;.idea文件 2、操作环境 3、操作步骤 &#xff08;1&#xff09;找到【Maven】工具按钮 &#xff08;2&#xff09;点图标&#xff0c;重复导入maven项目&am…

Pikachu漏洞练习平台之XXE(XML外部实体注入)

目录 什么是 XML&#xff1f; 什么是DTD&#xff1f; 什么是XEE&#xff1f; 常见payload 什么是 XML&#xff1f; XML 指可扩展标记语言&#xff08;EXtensible Markup Language&#xff09;&#xff1b; XML 不会做任何事情&#xff0c;而是用来结构化、存储以及传输信息…

promise时效架构升级方案的实施及落地 | 京东物流技术团队

一、项目背景 为什么需要架构升级 promise时效包含两个子系统&#xff1a;内核时效计算系统&#xff08;系统核心是时效计算&#xff09;和组件化时效系统&#xff08;系统核心是复杂业务处理以及多种时效业务聚合&#xff0c;承接结算下单黄金流程流量&#xff09;&#xff…

SPASS-参数估计与假设检验

参数估计 点估计 点估计用样本统计量的值直接作为总体参数的估计值。如用样本均值直接作为总体均值的估计值,用样本方差直接作为总体方差的估计值等。 常用的点估计法 (1)矩估计法 (2)极大似然估计法 (3)稳健估计法 区间估计 因为点估计直接用样本估计值作为总体参数…

苹果MAC安装绿盾出现问题,安装时没有出现填服务器地址的页面,现在更改不了也卸载不了绿盾 怎么处理?

环境: Mac mini M1 Mac os 11.0 绿盾v6.5 问题描述: 苹果MAC安装绿盾出现问题,安装时没有出现填服务器地址的页面,现在更改不了也卸载不了绿盾 怎么处理? 解决方案: 大部分企业是Windows和Mac终端混合使用,在进行文档加密管理时通常会遇到不兼容的现象,而为了统一…

Ubuntu 18.04无网络连接的n种可能办法

文章目录 网络图标消失&#xff0c;Ubuntu无网络连接VMware上Ubuntu18.04&#xff0c;桥接了多个网卡&#xff0c;其中一个用来上网&#xff0c;均设置为静态ip网络桥接链路没有接对路由不对 网络图标消失&#xff0c;Ubuntu无网络连接 sudo service network-manager stop sud…

python趣味编程-5分钟实现一个谷歌恐龙游戏(含源码、步骤讲解)

Python 恐龙游戏是为想要学习 Python 的初学者创建的。该项目系统使用了 Pygame 和 Random 模块。 Pygame 是一组跨平台的 Python 模块,专为编写视频游戏而设计。 Python 中的 Dino Game有一个任务记录,其中包含图片文档和 Python 内容(dino.py)。 GUI 使用 pygame 库。

Linux C 线程间同步机制

线程间同步机制 概述保护机制互斥锁创建互斥锁  pthread_mutex_init加锁  pthread_mutex_lock解锁  pthread_mutex_unlock删除锁  pthread_mutex_destroy 条件变量创建条件变量  pthread_cond_init激活条件变量  pthread_cond_signal等待条件变量  pthread_cond_…

Sentinel规则

一、服务熔断测试 例子: application.properties配置文件 server.port8083spring.application.nameorder#spring.cloud.nacos.discovery.server-addrhttp://192.168.44.64:80spring.cloud.nacos.discovery.server-addrlocalhost:8848spring.cloud.sentinel.transport.port999…