当前位置: 首页>行业 >

【教程科普】带命令行参数解析的C程序到底怎么写?

来源: 嵌入式物联网开发 | 时间: 2023-05-16 16:29:34 |

**带命令行参数解析的C程序到底怎么写?**

> 最近工作上,遇到这样一个问题:我需要写一个C语言的程序,这个程序要求带命令行输入,之前有了解一些这方面的知识,本文将带大家好好梳理一下,希望对大家有所帮助。

@[toc]# 1 写在前面


(资料图)

最近工作上,遇到这样一个问题:我需要写一个C语言的程序,这个程序要求带命令行输入,之前有了解一些这方面的知识,本文将带大家好好梳理一下,希望对大家有所帮助。

# 2 需求分析

如上面所说,具体的功能需求是这样的:

```c比如:命令行输入 ./test -i in.bin -o out.bin -f -v2或者 ./test -i in.bin -o out.bin -f -v表示的含义是: 执行test程序,输入一个in.bin文件,输出一个out.bin文件,-t表示强制执行(忽略错误), -v2表示使用第1版本功能,如果没有2只有-v,则使用默认的第1版本。```

整个功能需求比较简单,核心诉求就是能够从命令行参数中筛选出输入文件名和输出文件名,以及是否强制执行(忽略错误);同时判别使用的版本号。

# 3 编程实现

下面我们考虑在Linux平台下,使用C语言实现上述简单需求。

## 3.1 main函数的另一种写法

在某些C语言教科书里面,可能只会跟你说,main函数的原型是:

```cint main(void);```

但却没有告诉你,其实它还有另一种写法:

```cint main(int argc, const char *argv[]);```

如果你是一个细心的编程者,一定会发现,在不带命令行参数的时候,两种main函数的原型都可以跑出预期的效果。

但是,如果像本专题中的需求,那就不得不使用第二种原型接口来玩了,因为你从运行的命令行那里输入的参数列表,就会通过main函数的argc和argv来体现。

## 3.2 粗暴一点的方式来实现

我们先用粗暴一点的方式来实现:直接去遍历argv列表,一个个判断即可。示例代码如下:

```c#include#include#include

int main(int argc, char *argv[]){int i = 0;char *in = NULL;char *out = NULL;int is_force = 0;int version_n = 1;int is_found_in = 0;int is_found_out = 0;

for (i = 0; i < argc; i++) {//show all input paramprintf("param %d: %sn", i + 1, argv[i]);

if (!strcmp(argv[i], "-i")) { is_found_in = 1; continue;} else if (!strcmp(argv[i], "-o")) { is_found_out = 1; continue;} else if (!strcmp(argv[i], "-f")) { is_force = 1; printf("is_force: %dn", is_force);} else if (!strncmp(argv[i], "-v", 2)) { if (strlen(argv[i]) != 2) { version_n = atoi(argv[i] + 2); } printf("version_n: %dn", version_n);}

if (is_found_in) { in = argv[i]; printf("in -> %sn", argv[i]); is_found_in = 0;}

if (is_found_out) { out = argv[i]; printf("out -> %sn", argv[i]); is_found_out = 0;}}

return 0;}```

gcc编译后,运行结果如下:

```c./test -i in.bin -o out.bin -f -v2param 1: ./testparam 2: -iparam 3: in.binin -> in.binparam 4: -oparam 5: out.binout -> out.binparam 6: -fis_force: 1param 7: -v2version_n: 2

./test -i in.bin -o out.bin -f -vparam 1: ./testparam 2: -iparam 3: in.binin -> in.binparam 4: -oparam 5: out.binout -> out.binparam 6: -fis_force: 1param 7: -vversion_n: 1```

基本达到预期。

## 3.3 优雅一点的方式来实现

上面的方面太粗暴,有没有优雅一点的方式,当然有,了解一下getopt函数。

man一下大概看看:

```cGETOPT(1) User Commands GETOPT(1)

NAME getopt - parse command options (enhanced)

SYNOPSIS getopt optstring parameters getopt [options] [--] optstring parameters getopt [options] -o|--options optstring [options] [--] parameters

DESCRIPTION getopt is used to break up (parse) options in command lines for easy parsing by shell procedures, and to check for valid options. It uses the GNU getopt(3) routines to do this.

The parameters getopt is called with canbe divided into two parts: options which modify the way getopt will do the parsing (the options and the optstring in the SYNOPSIS), and the parameters which are to be parsed (parameters in the SYNOPSIS). The second part will start at the first non-option parameter that is not an option argument, or after the first occurrence of "--". If no "-o" or "--options" option is found in the first part, the first parameter of the second part is used as the short options string.

If the environment variable GETOPT_COMPATIBLE is set, or if the first parameter is not an option (does not start with a "-", the first format in the SYNOP‐ SIS), getopt will generate output that is compatible with that of other versions of getopt(1). It will still do parameter shuffling and recognize optional arguments (see section COMPATIBILITY for more information).

Traditional implementations of getopt(1) are unable to cope with whitespace and other (shell-specific) special characters in arguments and non-option parame‐ ters. To solve this problem, this implementation can generate quoted output which must once again be interpreted by the shell (usually by using the eval com‐ mand). This has the effect of preserving those characters, but you must call getopt in a way that is no longer compatible with other versions (the second or third format in the SYNOPSIS). To determine whether this enhanced version of getopt(1) is installed, a special test option (-T) can be used.

```

从这里我们可以看到它就是为解析命令行参数而诞生的。

我们来试一下用它来实现本例程中的功能需求:

```c#include#include#include

int main(int argc, char *argv[]){ int opt; char *in = NULL; char *out = NULL; int is_force = 0; int version_n = 1;

while ((opt = getopt(argc, argv, "i:o:fv::")) != -1) { switch (opt) { case "i": in = optarg; printf("Option i was selected, in: %sn", in); break;

case "o": out = optarg; printf("Option b was selected, out: %sn", out); break;

case "f": is_force = 1; printf("Option b was selected, force: %dn", is_force); break;

case "v": if (!optarg) { printf("Option c was selected with default value %dn", version_n); } else { printf("Option c was selected with value %dn", atoi(optarg)); } break;

default: fprintf(stderr, "Usage: %s [-i in] [-o out] [-f] [ -vn]n", argv[0]); exit(EXIT_FAILURE); } }

return 0;}```

编译一下,看调试结果:

```c./test -i in.bin -o out.bin -vOption i was selected, in: in.binOption b was selected, out: out.binOption c was selected with default value 1

./test -i in.bin -o out.bin -v -fOption i was selected, in: in.binOption b was selected, out: out.binOption c was selected with default value 1Option b was selected, force: 1

$./test -i in.bin -o out.bin -v2 -fOption i was selected, in: in.binOption b was selected, out: out.binOption c was selected with value 2Option b was selected, force: 1```

从调试的结果来看,基本是可以满足需求的。

## 3.4 更为优秀一点的方式来实现

其实还有一个getopt_long函数可以更加详细地描述和使用命令行参数,参考例程如下:

```c#include#include#include

int main(int argc, char *argv[]){ int opt; char *in = NULL; char *out = NULL; int is_force = 0; int version_n = 1;

struct option long_options[] = { {"in", required_argument, NULL, "i"}, {"out", required_argument, NULL, "o"}, {"force", no_argument, NULL, "f"}, {"version", optional_argument, NULL, "v"}, {NULL, 0, NULL, 0} };

while ((opt = getopt_long_only(argc, argv, "i:o:fv::", long_options, NULL)) != -1) { switch (opt) { case "i": in = optarg; printf("Option i was selected, in: %sn", in); break;

case "o": out = optarg; printf("Option b was selected, out: %sn", out); break;

case "f": is_force = 1; printf("Option b was selected, force: %dn", is_force); break;

case "v": if (!optarg) { printf("Option c was selected with default value %dn", version_n); } else { printf("Option c was selected with value %dn", atoi(optarg)); } break;

default: fprintf(stderr, "Usage: %s [-h] [-v] [-f file]n", argv[0]); exit(EXIT_FAILURE); } }

return 0;}```

编译之后,调试结果如下:

```c./test --in xxx.in --out xxx.out --force --version=2Option i was selected, in: xxx.inOption b was selected, out: xxx.outOption b was selected, force: 1Option c was selected with value 2

./test -i xxx.in -o xxx.out -f -v2Option i was selected, in: xxx.inOption b was selected, out: xxx.outOption b was selected, force: 1Option c was selected with value 2```

可以看到短参数和长参数是等价的,但是需要注意的是:option的长参数输入的方式是 **--xxx=yy**

否则会报错:

```c./test --in xxx.in --out xxx.out --force --version2Option i was selected, in: xxx.inOption b was selected, out: xxx.outOption b was selected, force: 1./test: unrecognized option "--version2"Usage: ./test [-h] [-v] [-f file]```

# 4 经验总结

- 了解main函数还有另一个写法,以便于支持带命令行参数的传入;- 学会使用getopt,你要搞个命令行参数解析,那不是so easy吗?- 还有个getopt_long满足命令行参数更优雅的需求,可以深入了解下。

# 5 文末福利

- 最近在推广一个《致敬未来的攻城狮计划》,旨在发现并扶持一批有志于往 **嵌入式开发领域** 发光发热的潜力股,感兴趣的朋友,可以了解下。- [【重磅推出】《致敬未来的工程师计划》,第2期计划火热进行中。。。-CSDN社区](https://bbs.csdn.net/topics/614375136)- 当下正进行一个 **嵌入式领域** 的定向博文征稿活动,有精美礼品赠送,欢迎大家关注了解下。- [【致敬未来的攻城狮计划】第2期定向征文,嵌入式的看过来。。。-CSDN社区](https://bbs.csdn.net/topics/614721973)- 我的技术社区(架构师李肯带你玩嵌入式),长期开展福利赠书(优质的技术图书)活动,感兴趣的朋友,可以重点关注下。- [架构师李肯(带你学嵌入式)社区丰富的社区活动等你来挑战-CSDN社区云](https://bbs.csdn.net/forums/recan-iot?typeId=2717194)审核编辑黄宇

关键词:

 

热文推荐

【教程科普】带命令行参数解析的C程序到底怎么写?

【教程科普】带命令行参数解析的C程序到底怎么写?

2023-05-16

短讯!万用王商品报价动态(2023-05-16)

交易商品牌 产地交货地最新报价万用王 粘度3000万荣盛化工有限公司河北河北省 沧州市14500元 吨

2023-05-16

中国—中亚峰会新闻中心启用 陕西特色元素引人入胜

5月18日至19日中国—中亚峰会将在西安举行千年丝路贯通东西,千年友谊再谱新篇热情的陕西已经做好准备迎接

2023-05-16

背上长粉刺是什么原因造成的图片_背上长粉刺是什么原因造成的

1、痘痘临床上其实叫粉刺,痘痘也叫痘痘,常见于年轻人。有些青少年,甚至三四十岁的中年人都会得,因为痘

2023-05-16

北京创新力量奔赴燕郊 世界观天下

北京创新力量奔赴燕郊

2023-05-16

对话中南建院董事长李霆:PLM让「建筑业」有机会诞生「苹果公司」 | 中国数智建筑36人

建筑产业往日辉煌已逝,焦虑与自由齐飞,主旋律转向科技。不过,就科技维度而言,建筑产业才刚刚破晓,

2023-05-16

凤尾鱼繁殖条件_凤尾鱼繁殖预兆图-全球新要闻

1、凤尾鱼快要下崽可能会出现精神状态比较异常,要么特别好动要么精神不佳,会躲在角落,食欲也会不佳,到

2023-05-16

当前快看:周二分析:防流感概念股报跌,中牧股份跌4.3%

周二分析:防流感概念股报跌,中牧股份跌4 3%,周二早盘南方财富网数据分析,防流感概念报跌,中牧股份(13

2023-05-16

工信部召开安全应急产业发展政策座谈会

App5月16日消息,安全应急产业发展政策座谈15日会在浙江杭州召开,工业和信息化部副部长徐晓兰出席会议并讲

2023-05-16

劳动法规定婚假的天数 婚假规定劳动法

今天来聊聊关于劳动法规定婚假的天数,婚假规定劳动法的文章,现在就为大家来简单介绍下劳动法规定婚假的天

2023-05-16

观焦点:国家统计局:1—4月份全国房地产开发投资同比下降6.2%,商品房销售面积下降0.4%,销售额增长8.8%

金融界5月16日消息国家统计局数据显示,1—4月份,全国房地产开发投资35514亿元,同比下降6 2%(按可比口

2023-05-16

北约在亚太手越伸越长(观象台)

近日,日本外相林芳正在接受美媒采访时证实,日本政府正就在东京开设北约联络处一事谈判。据日媒报道,该联

2023-05-16

世界简讯:跨越山海重逢 续写“无锡旅情”新篇章

近期,“无锡旅情携手未来”无锡(东京)经贸文化合作交流会在日本东京成功举办。

2023-05-16

天天要闻:王导:黄金4小时中轨压制,持仓看跌中

搞来搞去金价还在原点空单还在金价还是在4小时中轨下方我会继续看空金价在4小时中轨下方想要上涨还是很困难

2023-05-16

磁控仿鱼微型机器人实现复杂运动的高效学习

5月8日,中国科学院深圳先进技术研究院集成所智能仿生研究中心的徐升和徐天添研究团队合作,提出了一套针对

2023-05-16

基于新一代电动车平台打造 丰田发布新车计划 全球热点

基于新一代电动车平台打造丰田发布新车计划日前,据丰田2023财年财报会,丰田汽车计划推出10款纯电动车型,

2023-05-16

所有者权益合计的公式怎么算的_所有者权益合计的公式 微头条

1、所有者权益合计的公式如下:所有者权益合计=经营收入-经营费用-生产性固定资产折旧-生产税+出租房屋净收

2023-05-16

atkex_cmd.exe已停止工作怎么解决_atkex cmd exe已停止工作-天天快看

1、解决方法:首先,右键点击“计算机”图标,如图所示。2、2、然后点击弹出选项中的【属性】,如图所示。3

2023-05-16

【世界播资讯】中手游(00302.HK):5月15日南向资金减持50.4万股

5月15日北向资金减持50 4万股中手游(00302 HK)。近5个交易日中,获南向资金减持的有5天,累计净减持994 2

2023-05-16

浙江篮球,别为0:4沮丧,那是明天的动力

5月15日晚,2022-2023年CBA总决赛落幕,浙江稠州金租男篮以0:4不敌辽宁男篮,获本赛季亚军。虽然总决赛落败,

2023-05-16

资讯

北京推出14条秋游文化线路

金秋时节,北京市文化和旅游局以赏银杏品文化为主题,推出14条“叶落的季节——漫步北京赏银杏品文化主题线路”,邀市民和游客以步行、骑行

2021-10-27     
基因编辑发力 培育高质量人源化供体猪

此次人体试验,仅仅验证了基因编辑猪克服异种器官移植的超急性排斥反应,还需解决延迟性排斥反应、消耗性血栓等问题。但通过这次试验,能更

2021-10-27     
中国经济高质量发展步伐稳健 长期向好基本面未变

在全球疫情走势和经济走势趋于复杂的背景下,中国经济巨轮将驶向何方,举世关注。2020年10月26日至29日,党的十九届五中全会在京举行,明确

2021-10-27     
南美解放者杯决赛允许近4.5万观众入场

南美洲足联主席多明格斯25日与今年解放者杯决赛对阵的两支俱乐部负责人会晤,宣布决赛现场观众人数增加到球场容量的75%,即近4 5万人。今年

2021-10-27     
22年从警生涯 面对荣誉他说不要给我报功

9月24日,时任安徽省安庆市公安局迎江分局刑警大队大要案中队中队长周磊因在工作中激烈搏斗引发心源性猝死,倒在了工作岗位上,经医院抢救

2021-10-27     
走近冬奥|五棵松体育中心场馆“黑科技”全面上岗 助力冬

“相约北京”冰球国内测试活动将于2021年11月7日至10日在五棵松体育中心场馆举行,在疫情防控方面,场馆引入了诸多“黑科技”,为防疫安全

2021-10-27