我记不住的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 */   optwhile ((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: 0f_append: 0f_delete: 0f_create: 1
f_verbose: 1
./a.out --verbose --append --create --add --delete
    f_add: 1f_append: 1f_delete: 1f_create: 1
f_verbose: 1
./a.out --v --c --ap --ad --d
    f_add: 1f_append: 1f_delete: 1f_create: 1
f_verbose: 1
./a.out -v -c -d -a
Unknown option v
Unknown option c
Unknown option d
Unknown option af_add: 0f_append: 0f_delete: 0f_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;// 默认为0static 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

3.Mead's Guide To getopt

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

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

相关文章

adb手机调试常用命令

查看手机型号 adb shell getprop ro.product.model 查看电池状况 adb shell dumpsys battery 查看分辨率 adb shell wm size 查看屏幕密度 adb shell wm density 查看显示屏参数 adb shell dumpsys window displays 查看android_id adb shell settings get secure android…

Elasticsearch:运用向量搜索通过图像搜索找到你的小狗

作者&#xff1a;ALEX SALGADO 你是否曾经遇到过这样的情况&#xff1a;你在街上发现了一只丢失的小狗&#xff0c;但不知道它是否有主人&#xff1f; 了解如何使用向量搜索或图像搜索来做到这一点。 通过图像搜索找到你的小狗 您是否曾经遇到过这样的情况&#xff1a;你在街…

V10服务器安装virt-manage

kvm是什么 KVM(Kernel-based Virtual Machine, 即内核级虚拟机) 是一个开源的系统虚拟化模块。它使用Linux自身的调度器进行管理&#xff0c;所以相对于Xen&#xff0c;其核心源码很少。目前KVM已成为学术界的主流VMM之一&#xff0c;它包含一个为处理器提供底层虚拟化 可加载…

概率论和数理统计(三)数理统计基本概念

前言 “概率论”是给定一个随机变量X的分布F(x),然后求某事件A概率 P ( x ∈ A ) P(x \in A) P(x∈A)或者随机变量X的数字特征.“统计”是已知一组样本数据 { x 1 , x 2 , . . . x n } \{x_1,x_2,...x_n\} {x1​,x2​,...xn​},去求分布F(x) 统计的基本概念 在统计中&#x…

Vue3-admin-template 框架实现表单身份证获取到 出生年月、性别

一. 首先需效验输入身份证信息是否正确&#xff1a; const sfzhChange () > {// 效验身份证号格式const reg /^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; }; 二.绑定输入框 input 事件&#xff1a; <el-form-item label&q…

监控直流防雷浪涌保护器综合方案

监控系统是一种广泛应用于安防、交通、工业、军事等领域的信息系统&#xff0c;它通过摄像机、传输线路、监控中心等设备&#xff0c;实现对目标区域的实时监视和控制。然而&#xff0c;监控系统也面临着雷电的威胁&#xff0c;雷电可能通过直击雷、感应雷、雷电波侵入等途径&a…

Linux服务器安装Dotnet8

1. 下载dotnet8 sdk 下载 .NET 8.0 SDK (v8.0.100) - Linux x64 Binaries 拿到 dotnet-sdk-8.0.100-linux-x64.tar.gz 文件 2. 把文件上传到 /usr/local/software 目录 mkdir -p /usr/local/software/dotnet8 把文件拷贝过去 mv dotnet-sdk-8.0.100-linux-x64.tar.gz /usr/loc…

安装SSL证书有什么意义?

在当今的数字化时代&#xff0c;网络安全已经成为了一个重要的议题。为了保护网站和用户数据的安全&#xff0c;许多网站都选择了安装SSL证书。同时&#xff0c;很多用户不明白安装SSL证书到底有什么意义&#xff1f; 一、网站实现加密传输 用户通过http协议访问网站时&#x…

vue使用navigator.mediaDevices.getUserMedia调用相机功能

目录 前言&#xff1a; API&#xff1a; API简单示例&#xff1a; 拍照功能 实现效果&#xff1a; 前言&#xff1a; 本文将介绍Vue中如何使用navigator.mediaDevices.getUserMedia调用相机功能&#xff0c;实现拍照使用实例&#xff0c;需要的朋友可以参考一下。 注意…

深度学习YOLOv5车辆颜色识别检测 - python opencv 计算机竞赛

文章目录 1 前言2 实现效果3 CNN卷积神经网络4 Yolov56 数据集处理及模型训练5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习YOLOv5车辆颜色识别检测 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0…

linux高级篇基础理论一(详细文档、Apache,网站,MySQL、MySQL备份工具)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…

VS2022升级之后,原有项目出现异常

最近对VS2022做了升级&#xff0c;发现之前开发的WebApi&#xff08;使用Net5&#xff09;调试运行报错&#xff1a; 根据提示的错误信息也在网上查找了一些资料&#xff0c;均无法正常解决&#xff0c;偶然发现问题是因为VS2022升级之后&#xff0c;不再支持Net5&#xff0c;…

【开源】基于Vue和SpringBoot的固始鹅块销售系统

项目编号&#xff1a; S 060 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S060&#xff0c;文末获取源码。} 项目编号&#xff1a;S060&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固…

论文技巧2

目录 1 找基准模型2 找模块小论文的三个实验怎么做对比试验Sota的挑选对⽐论⽂结果的获取3 消融实验什么是消融实验怎么做消融实验4 实例分析怎么做实例分析小论文必备三张图1 找基准模型 2 找模块 小论文的三个实验 怎么做对比试验

高性能音乐流媒体服务Diosic

什么是 Diosic ? Diosic 是一个开源的基于网络的音乐收集服务器和流媒体。主要适合需要部署在硬件规格不高的服务器上的用户。Diosic 是使用 Rust 开发的&#xff0c;具有低内存使用率和高性能以及用于流媒体音乐的非常干净的界面。 安装 在群晖上以 Docker 方式安装。 在注…

基于JavaWeb+SpringBoot+Vue医疗器械商城微信小程序系统的设计和实现

基于JavaWebSpringBootVue医疗器械商城微信小程序系统的设计和实现 源码获取入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码获取入口 前言 摘 要 目前医疗器械行业作为医药行业的一个分支&#xff0c;发展十分迅速。…

Sql Prompt 10下载安装图文教程

在操作过程中&#xff0c;请暂时关闭你的防病毒软件&#xff0c;以免其误报导致操作失败。 资源 SQL Prompt 10 https://www.aliyundrive.com/s/QuMWkvE1Sv6 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&…

【数据结构】树与二叉树(十六):二叉树的基础操作:插入结点(算法Insert)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

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

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

三大开源向量数据库大比拼

向量数据库具有一系列广泛的好处&#xff0c;特别是在生成式人工智能方面&#xff0c;更具体地说&#xff0c;是在大语言模型&#xff08;LLM&#xff09;方面。这些好处包括先进的索引和精确的相似度搜索&#xff0c;有助于交付强大的先进项目。 本文将对三种开源向量数据库&…