命令行选项解析函数(C语言):getopt()和getopt_long()

上午在看源码项目 webbench 时,刚开始就被一个似乎挺陌生函数 getopt_long() 给卡住了,说实话这函数没怎么见过,自然不知道这哥们是干什么的。于是乎百度了一番,原来是处理命令行选项参数的,的确,正规点的大型程序一般第一步就是处理命令行参数的,接着才是主干程序。在百度和 man 的帮助下,找到了具体使用方法和解释,二话不说赶紧学习一下,并总结出文档记录一下。

    平时在写程序时常常需要对命令行参数进行处理,因为参数少,自己解析就可以搞定;如果命令行个数比较多时,如果按照顺序一个一个定义参数含义很容易造成混乱,而且如果程序只按顺序处理参数的话,一些“可选参数”的功能将很难实现,这个问题在 linux 中用 getopt 等函数可以优雅地解决。

一、查询linux命令手册:

复制代码
复制代码
#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;
复制代码
复制代码

先拿最简单的 getopt 函数开刀,getopt_long 只是前者的增强版,功能多点而已。

二、getopt函数

1、定义

int getopt(int argc, char * const argv[], const char *optstring);

2、描述

getopt是用来解析命令行选项参数的,但是只能解析短选项: -d 100,不能解析长选项:--prefix

3、参数

argc:main()函数传递过来的参数的个数
argv:main()函数传递过来的参数的字符串指针数组
optstring:选项字符串,告知 getopt()可以处理哪个选项以及哪个选项需要参数

4、返回

如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回 -1;如果遇到选项字符不在 optstring 中,返回字符 '?';如果遇到丢失参数,那么返回值依赖于 optstring 中第一个字符,如果第一个字符是 ':' 则返回':',否则返回'?'并提示出错误信息。

5、下边重点举例说明optstring的格式意义:

char*optstring = “ab:c::”;
单个字符a         表示选项a没有参数            格式:-a即可,不加参数
单字符加冒号b:     表示选项b有且必须加参数      格式:-b 100或-b100,但-b=100错
单字符加2冒号c::   表示选项c可以有,也可以无     格式:-c200,其它格式错误

上面这个 optstring 在传入之后,getopt 函数将依次检查命令行是否指定了 -a, -b, -c(这需要多次调用 getopt 函数,直到其返回-1),当检查到上面某一个参数被指定时,函数会返回被指定的参数名称(即该字母)

optarg —— 指向当前选项参数(如果有)的指针。
optind —— 再次调用 getopt() 时的下一个 argv指针的索引。
optopt —— 最后一个未知选项。
opterr ­—— 如果不希望getopt()打印出错信息,则只要将全域变量opterr设为0即可。

以上描述的并不生动,下边结合实例来理解:

6、实例:

复制代码
复制代码
#include<stdio.h>
#include<unistd.h>
#include<getopt.h>
int main(intargc, char *argv[])
{int opt;char *string = "a::b:c:d";while ((opt = getopt(argc, argv, string))!= -1){  printf("opt = %c\t\t", opt);printf("optarg = %s\t\t",optarg);printf("optind = %d\t\t",optind);printf("argv[optind] = %s\n",argv[optind]);}  
}
复制代码
复制代码

编译上述程序并执行结果:

输入选项及参数正确的情况

dzlab:~/test/test#./opt -a100 -b 200 -c 300 -d
opt = a         optarg = 100            optind = 2              argv[optind] = -b
opt = b         optarg = 200            optind = 4              argv[optind] = -c
opt = c         optarg = 300            optind = 6              argv[optind] = -d
opt = d         optarg = (null)         optind = 7              argv[optind] = (null)

或者这样的选项格式(注意区别):

dzlab:~/test/test#./opt -a100 -b200 -c300 -d 
opt = a         optarg = 100            optind = 2              argv[optind] = -b200
opt = b         optarg = 200            optind = 3              argv[optind] = -c300
opt = c         optarg = 300            optind = 4              argv[optind] = -d
opt = d         optarg = (null)         optind = 5              argv[optind] = (null)

选项a是可选参数,这里不带参数也是正确的

dzlab:~/test/test#./opt -a -b 200 -c 300 -d   
opt = a         optarg = (null)         optind = 2              argv[optind] = -b
opt = b         optarg = 200            optind = 4              argv[optind] = -c
opt = c         optarg = 300            optind = 6              argv[optind] = -d
opt = d         optarg = (null)         optind = 7              argv[optind] = (null)

输入选项参数错误的情况

dzlab:~/test/test#./opt -a 100 -b 200 -c 300 -d
opt = a         optarg = (null)         optind = 2              argv[optind] = 100
opt = b         optarg = 200            optind = 5              argv[optind] = -c
opt = c         optarg = 300            optind = 7              argv[optind] = -d
opt = d         optarg = (null)         optind = 8              argv[optind] = (null)

导致解析错误,第一个 optarg = null,实际输入参数 100,由于格式不正确造成的(可选参数格式固定)

参数丢失,也会导致错误,c选项是必须有参数的,不加参数提示错误如下:

dzlab:~/test/test#./opt -a -b 200 -c      
opt = a         optarg = (null)         optind = 2              argv[optind] = -b
opt = b         optarg = 200            optind = 4              argv[optind] = -c
./opt: optionrequires an argument -- 'c'
opt = ?         optarg = (null)         optind = 5              argv[optind] = (null)

这种情况,optstring 中第一个字母不是':',如果在 optstring 中第一个字母加':',则最后丢失参数的那个选项 opt 返回的是':',不是'?',并且没有提示错误信息,这里不再列出。

命令行选项未定义,-e选项未在optstring中定义,会报错:

dzlab:~/test/test#./opt -a -b 200 -e
opt = a         optarg = (null)         optind = 2              argv[optind] = -b
opt = b         optarg = 200             optind = 4              argv[optind] = -e
./opt: invalidoption -- 'e'
opt = ?         optarg = (null)         optind = 5              argv[optind] = (null)

到这里应该已经把getopt函数的功能讲解清楚了吧,下边来说说 getopt_long 函数,getopt_long 函数包含了 getopt 函数的功能,并且还可以指定"长参数"(或者说长选项),与 getopt 函数对比,getopt_long 比其多了两个参数:

三、getopt_long函数

1、定义

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

2、描述

包含 getopt 功能,增加了解析长选项的功能如:--prefix --help

3、参数

longopts    指明了长参数的名称和属性
longindex   如果longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值

4、返回

对于短选项,返回值同getopt函数;对于长选项,如果flag是NULL,返回val,否则返回0;对于错误情况返回值同getopt函数
5、struct option
struct option {
const char  *name;       /* 参数名称 */
int          has_arg;    /* 指明是否带有参数 */
int          *flag;      /* flag=NULL时,返回value;不为空时,*flag=val,返回0 */
int          val;        /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */
}; 

6、参数说明:

has_arg  指明是否带参数值,其数值可选:
no_argument         表明长选项不带参数,如:--name, --help
required_argument  表明长选项必须带参数,如:--prefix /root或 --prefix=/root
optional_argument  表明长选项的参数是可选的,如:--help或 –prefix=/root,其它都是错误

接着看一下实例操作会更加深刻地理解:

7、实例:

复制代码
复制代码
int main(intargc, char *argv[])
{int opt;int digit_optind = 0;int option_index = 0;char *string = "a::b:c:d";static struct option long_options[] ={  {"reqarg", required_argument,NULL, 'r'},{"optarg", optional_argument,NULL, 'o'},{"noarg",  no_argument,         NULL,'n'},{NULL,     0,                      NULL, 0},}; while((opt =getopt_long_only(argc,argv,string,long_options,&option_index))!= -1){  printf("opt = %c\t\t", opt);printf("optarg = %s\t\t",optarg);printf("optind = %d\t\t",optind);printf("argv[optind] =%s\t\t", argv[optind]);printf("option_index = %d\n",option_index);}  
}
复制代码
复制代码

编译上述程序并执行结果:

正确输入长选项的情况

dzlab:~/test/test#./long --reqarg 100 --optarg=200 --noarg
opt = r optarg =100     optind = 3   argv[optind] = --optarg=200  option_index = 0
opt = o optarg =200     optind = 4   argv[optind] = --noarg        option_index = 1
opt = n optarg =(null) optind = 5    argv[optind] =(null)          option_index = 2

或者这种方式:

dzlab:~/test/test#./long –reqarg=100 --optarg=200 --noarg
opt = r optarg =100     optind = 2   argv[optind] = --optarg=200  option_index = 0
opt = o optarg =200     optind = 3   argv[optind] = --noarg        option_index = 1
opt = n optarg =(null) optind = 4    argv[optind] =(null)          option_index = 2

可选选项可以不给参数

dzlab:~/test/test#./long --reqarg 100 --optarg --noarg   
opt = r optarg =100     optind = 3     argv[optind] = --optarg option_index = 0
opt = o optarg =(null) optind = 4      argv[optind] =--noarg   option_index = 1
opt = n optarg =(null) optind = 5      argv[optind] =(null)     option_index = 2

输入长选项错误的情况

dzlab:~/test/test#./long --reqarg 100 --optarg 200 --noarg 
opt = r optarg =100     optind = 3     argv[optind] = --optarg  option_index= 0
opt = o optarg =(null) optind = 4      argv[optind] =200        option_index = 1
opt = n optarg =(null) optind = 6      argv[optind] =(null)     option_index = 2

这时,虽然没有报错,但是第二项中 optarg 参数没有正确解析出来(格式应该是 —optarg=200)

必须指定参数的选项,如果不给参数,同样解析错误如下:

dzlab:~/test/test#./long --reqarg --optarg=200 --noarg    
opt = r optarg =--optarg=200  optind = 3 argv[optind] =--noarg  option_index = 0
opt = n optarg =(null)         optind = 4 argv[optind] =(null)    option_index = 2

长选项的举例说明暂且就这么多吧,其它如选项错误、缺参数、格式不正确的情况自己再试验一下。

四、getopt_long_only函数

getopt_long_only 函数与 getopt_long 函数使用相同的参数表,在功能上基本一致,只是 getopt_long 只将 --name 当作长参数,但 getopt_long_only 会将 --name 和 -name 两种选项都当作长参数来匹配。getopt_long_only 如果选项 -name 不能在 longopts 中匹配,但能匹配一个短选项,它就会解析为短选项。

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

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

相关文章

夺命雷公狗ThinkPHP项目之----企业网站2之数据库的快速设计

我们在一个项目的时候&#xff0c;花费最多事件的估计还是数据库的时间了&#xff0c;我们的数据库暂时就这样设计好了&#xff1a; 暂时我们的数据库就这样设计好了用下先,建好后如下所示&#xff1a; 转载于:https://www.cnblogs.com/leigood/p/5411017.html

6月份美国域名总量新增近5.4万个 环比减少51%

中国IDC评述网07月03日报道&#xff1a;据域名统计机构WebHosting.info公布的数据显示&#xff0c;截至2012年6月25日&#xff0c;美国域名总量达到了79,632,920个&#xff0c;域名增幅较小。下面&#xff0c;IDC评述网与大家一起关注6月份美国域名注册量最新情况。 &#xff0…

vue+element-ui大文件的分片上传和断点续传js-spark-md5和browser-md5-file

注意&#xff1a;以下共两份代码片段&#xff0c;第一份为原博主链接代码&#xff0c;第二份自己写的整体代码&#xff08;比较乱&#xff09; 1.参考 https://www.cnblogs.com/kelelipeng/p/10158599.html &#xff08;js-spark-md5和browser-md5-file&#xff09; 和 https:…

Fedora 20 安装试用体验全程讲解

From: http://www.jb51.net/os/Fedora/177583.html Fedora 20在两次跳票后正式发布&#xff0c;主要特性包括&#xff1a;远程桌面方案X2Go&#xff1b;网络管理器支持扩大绑定和桥接功能&#xff1b;改进3D打印机支持等&#xff0c;本文中&#xff0c;作者对Fedora 20 进行安装…

NUC972配置为支持NFS

为了使用NFS进行调试。需要安装NFS server,具体的流程在上一篇博文中有较为详细的介绍。在配置内核时需要做如下的操作&#xff1a; 对于Boot option中的处理&#xff0c;可以不用写在env.txt配置也是可以的。 baudrate115200 bootargsnoinitrd consolettyS0,115200 r…

【Fedora20】 samba配置

From: http://blog.163.com/shi_shun/blog/static/23707849201452641312640/ 1、安装前的准备 关闭防火墙 //不关的后果是windows看不到本机 systemctl stop firewalld //暂时关闭防火墙 systemctl disable firewalld //开机禁止启动 关闭selinux //不关…

【操作系统】实验二 作业调度模拟程序

一、目的和要求 1. 实验目的 &#xff08;1&#xff09;加深对作业调度算法的理解&#xff1b; &#xff08;2&#xff09;进行程序设计的训练。 2&#xff0e;实验要求 用高级语言编写一个或多个作业调度的模拟程序。 单道批处理系统的作业调度程序。作业一投入运行&#xff0…

Nuc972使用NandFlash时,uboot所需要的改动

先贴错误现象。 做工程&#xff0c;我发现&#xff0c;就应该里面记录下来&#xff0c;哪怕再简单&#xff0c;一两个月后&#xff0c;果断忘&#xff0c;最不能相信自己的脑子。不好使~~~~

手把手教你用Python爬虫煎蛋妹纸海量图片

我们的目标是用爬虫来干一件略污事情 最近听说煎蛋上有好多可爱的妹子&#xff0c;而且爬虫从妹子图抓起练手最好&#xff0c;毕竟动力大嘛。而且现在网络上的妹子很黄很暴力&#xff0c;一下接受太多容易营养不量&#xff0c;但是本着有人身体就比较好的套路&#xff0c;特意分…

chrome浏览器的跨域设置,前端修改跨域问题

原文&#xff1a;https://www.cnblogs.com/laden666666/p/5544572.html 做前后分离的webapp开发的时候&#xff0c;出于一些原因往往需要将浏览器设置成支持跨域的模式&#xff0c;好在chrome浏览器就是支持可跨域的设置&#xff0c;网上也有很多chrome跨域设置教程。但是新版本…

Server 2012 Hyper-v新功能之二:自动化支持技术

Server 2012 Hyper-v新功能之一&#xff1a;客户端 Hyper-V Windows PowerShell 是在 Windows Server 中执行自动化任务的脚本解决方案&#xff0c;新的适用于 Windows PowerShell 的 Hyper-V cmdlet 为 IT 专业人员提供了一种简单的方法&#xff0c;能够在 Windows Server 201…

SecureCRTSecureFX_HH_x64_7.0.0.326 crt部署项目到服务器

1.使用crt 2.输入服务器ip和账号 3.命令 cd 空格 /item/qd 回车进入到规定好的前端代码目录下 ls 查看目录下的文件 4.rm -rf 文件名称/或者目录名称&#xff08;空格删除多个、&#xff09; rm 空格 -rf 空格 *.zip 删除所有的zip rz 上传新的zip包 6。解压 unzip 空…

ant中的table和pagination表格分页结合使用 手写分页

表格部分 <a-table:row-selection"rowSelection" :columns"columns":data-source"data"class"components-table-demo-nested"change"onChangeTable":scroll"{ x:1600 ,y:500}":pagination"pagination&qu…

poj3692

最大独立集&#xff0c;把不认识的男女看成是有矛盾的&#xff0c;要选出一些互相没有矛盾的男女。 View Code #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std;#define maxn 205bool g[maxn][max…

在项目里交叉使用Swift和OC

From: http://blog.csdn.net/huangchentao/article/details/35278663 Swift and Objective-C in the Same Project 在项目里交叉使用Swift和OC Swift与OC的兼容性使得你可以在项目里使用SwiftOC的方式编写应用程序&#xff0c;称为混合匹配(mix and match)&#xff0c;用这种…

WireShark抓包,may be caused by ip checksum offload的解决办法

From: http://blog.csdn.net/yanjiee/article/details/8051494 今天在用WireShark抓包的时候&#xff0c;发现由本机发出去的包都是黑底红字&#xff0c;点进去看了一下发现都是报“may be caused by ip checksum offload”这样一个错误。 于是在网络上搜了一下关于Checksum o…

使用Dezender对zend加密后的php文件进行解密

在开发中需要修改一些php文件&#xff0c;部分是通过zend加密的&#xff0c;记事本打开之后是这样的&#xff1a; 此时需要使用Dezender进行解密&#xff0c;下载链接如下&#xff1a; Dezender.7z 下载后解压到C盘(路径不要带有中文)&#xff0c;如解压到其他位置&#xff0c;…

vue-cli3引入第三方的js依赖包并使用其方法

注意&#xff1a;引入第三方的包有两种&#xff0c;一种是做特殊要求必须如何引用的&#xff1b;一种是没有要求的 情况1&#xff1a;js包要求了如何引入的&#xff0c;按照其文档的方式引入和使用即可 1.1直接在indes.html按照要求引入 1.2使用方法 情况2&#xff1a;没…