最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上。今天听了学长说到getopt函数,才发现原来c里面还有一个专门解决参数处理的函数,查询了相关资料,这里简单总结一下。

使用int main( int argc, char *argv[] )(或int main( int argc, char **argv ))时,系统将把用户输入的参数通过argc和argv引入程序中,argc为参数的个数,argv是指向参数的指针数组,其中第一个参数为自身程序文件名。

这里我们使用getopt() 函数对传入的参数进行处理,getopt()位于 unistd.h 系统头文件中,函数原型可以在man中查到,大家可以使用下面指令查看getopt的man手册

man  getopt

getopt的函数原型如下:

#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg;
extern int optind, opterr, optopt;

这里引用IBM对于其的解释,原文链接在这。我对其中部分错误做了更改,

给定了命令参数的数量 (argc)、指向这些参数的数组 (argv) 和选项字符串 (optstring) 后,getopt() 将返回第一个选项,并设置一些全局变量。使用相同的参数再次调用该函数时,它将返回下一个选项,并设置相应的全局变量。如果不再有识别到的选项,将返回 -1,此任务就完成了。

getopt() 所设置的全局变量包括:

extern char *optarg;  //选项的参数指针
       extern int optind,   //下一次调用getopt的时,从optind存储的位置处重新开始检查选项。 
       extern int opterr,  //当opterr=0时,getopt不向stderr输出错误信息。
       extern int optopt;  //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt中,getopt返回'?'

对于每个选项,选项字符串 (optstring) 中都包含一个对应的字符。具有参数的选项后面跟有一个 : 字符。如果一个选项后面紧跟2个冒号(::),表示该选项和参数之间不使用空格隔开;

可以重复调用 getopt(),直到其返回 -1 为止;任何剩下的命令行参数通常视为文件名或程序相应的其他内容。

我们知道,一般程序的选项分为两种:带关联值的和不带关联值的,

在解析参数的时候,我们希望的是:从一堆参数中把我们要的选项和选项关联值分别找到并存到相对应的地方供我们使用,并且把其他参数找出来供我们调用。

getopt完美实现这一点。

我们在测试的时候,定义了一个全局变量来存储参数值,

typedef struct parameter
{
int a; //参数a
int b; //参数b
char *b_pri; //参数b的关联值
int c; //参数c
char *c_pri; //参数c的关联值
}par;

如果遇到了其他选项,getopt() 将显示一个错误消息,程序将在显示了使用方法消息后退出。因此optString应该为

static const char *optstring = "ab:c::?";

程序运行之前,我们先对参数初始化,设定其初始值。

    //参数初始化
opt.a = ;
opt.b = ;
opt.b_pri = NULL;
opt.c = ;
opt.c_pri = NULL;

接下来就简单的把参数使用getopt处理,最后输出最后的参数就行了,看看我们的测试程序。

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> typedef struct parameter
{
int a; //参数a
int b; //参数b
char *b_pri; //参数b的关联值
int c; //参数c
char *c_pri; //参数c的关联值
}par; int main( int argc, char **argv )
{
int i; //循环变量
par opt; //参数
int flag = ; //循环退出标志位 //参数初始化
opt.a = ;
opt.b = ;
opt.b_pri = NULL;
opt.c = ;
opt.c_pri = NULL; //参数检测
if (argc == )
{
printf("您没有设置选项!\n");
exit(); }
//输出未处理的参数
printf("系统传入的参数为:");
for ( i = ; i < argc; i++)
{
printf("%s ",argv[i]);
}
printf("\n"); //循环处理传入参数
while(flag != -)
{
//调用getopt处理参数
switch(getopt( argc, argv, "ab:c::?"))
{
case 'a':
opt.a = ;
break;
case 'b':
opt.b = ;
opt.b_pri = optarg;
break;
case 'c':
opt.c = ;
opt.c_pri = optarg;
break;
case -:
flag = -;
break;
default:
break;
}
} if( optind != argc)
{
printf("参数中非程序选项的有:");
for (i = optind; i < argc; i++)
{
printf("%s\t",argv[i]);
}
printf("\n");
} //输出解析结果
printf("解析到程序启动后启用的选项有:");
if (opt.a == )
printf("a,");
if (opt.b == )
printf("b(参数为:%s),",opt.b_pri);
if (opt.c == )
printf("c(参数为:%s),",opt.c_pri);
printf("\n"); //处理后,输出全部参数与原来对比
printf("使用getopt后,系统参数变为为:");
for ( i = ; i < argc; i++)
{
printf("%s ",argv[i]);
}
printf("\n"); return ;
}

保存后,编译运行。

$ ./a.out -a -b    -h -c1
系统传入的参数为:-a -b -h -c1
./a.out: invalid option -- 'h'
参数中非程序选项的有:
解析到程序启动后启用的选项有:a,b(参数为:),c(参数为:),
使用getopt后,系统参数变为为:-a -b -h -c1

其中,我们传入的参数被全部解析出来,非正常选项"-h"直接显示出来,如果大家不希望非正常参数显示出来,或者希望自己处理非正常参数,可以在设置getopt中全域变量opterr = 0,在optstring的时候不加入?,例如

opterr = ;

static const char *optstring = "ab:c::";

那么程序在检测到未知选项会返回?,我们可以这样处理

opterr = ;    //getopt不输出错误参数

...其他程序段...

//循环处理传入参数
while(flag != -)
{
//调用getopt处理参数
switch(getopt( argc, argv, "ab:c::"))
{
case 'a':
opt.a = ;
break;
case 'b':
opt.b = ;
opt.b_pri = optarg;
break;
case 'c':
opt.c = ;
opt.c_pri = optarg;
break;
case '?':
printf("出现非正常选项:%c\n",optopt);
break;
case -:
flag = -;
break;
default:
break;
}
}

程序源代码如下:

 #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> typedef struct parameter
{
int a; //参数a
int b; //参数b
char *b_pri; //参数b的关联值
int c; //参数c
char *c_pri; //参数c的关联值
}par; int main( int argc, char **argv )
{
int i; //循环变量
par opt; //参数
int flag = ; //循环退出标志位 //参数初始化
opt.a = ;
opt.b = ;
opt.b_pri = NULL;
opt.c = ;
opt.c_pri = NULL;
opterr = ; //getopt不输出错误参数 //参数检测
if (argc == )
{
printf("您没有设置选项!\n");
exit(); }
//输出未处理的参数
printf("系统传入的参数为:");
for ( i = ; i < argc; i++)
{
printf("%s ",argv[i]);
}
printf("\n"); //循环处理传入参数
while(flag != -)
{
//调用getopt处理参数
switch(getopt( argc, argv, "ab:c::"))
{
case 'a':
opt.a = ;
break;
case 'b':
opt.b = ;
opt.b_pri = optarg;
break;
case 'c':
opt.c = ;
opt.c_pri = optarg;
break;
case '?':
printf("出现非正常选项:%c\n",optopt);
break;
case -:
flag = -;
break;
default:
break;
}
} if( optind != argc)
{
printf("参数中非程序选项的有:");
for (i = optind; i < argc; i++)
{
printf("%s\t",argv[i]);
}
printf("\n");
} //输出解析结果
printf("解析到程序启动后启用的选项有:");
if (opt.a == )
printf("a,");
if (opt.b == )
printf("b(参数为:%s),",opt.b_pri);
if (opt.c == )
printf("c(参数为:%s),",opt.c_pri);
printf("\n"); //处理后,输出全部参数与原来对比
printf("使用getopt后,系统参数变为为:");
for ( i = ; i < argc; i++)
{
printf("%s ",argv[i]);
}
printf("\n"); return ;
}

这样的话,上面同样的参数下,运行结果如下:

$ ./a.out -a -b    -h -c1
系统传入的参数为:-a -b -h -c1
出现非正常选项:h
参数中非程序选项的有:
解析到程序启动后启用的选项有:a,b(参数为:),c(参数为:),
使用getopt后,系统参数变为为:-a -b -h -c1

ok了,其实还有一个比getopt更好的一个选择,就是getopt_long,它可以支持长选项,因为这篇博文呢针对getopt的,所以我就不多做介绍,大家可以查man手册,或者等待我不知道什么时候的下次更新吧。

如何使用getopt()函数解析参数的更多相关文章

  1. getopt函数

    getopt -- 解析命令的可选项   [说明]getopt只是一个简单的解析命令可选项的函数,只能进行简单的格式命令解析,格式如下:   1.形如:cmd [-a][-b] //对短选项的解析: ...

  2. 使用getopt_long来解析参数的小函数模板

    getopt_long原型 #define no_argument 0 #define required_argument 1 #define optional_argument 2 struct o ...

  3. getopt函数的使用——分析命令行参数

    getopt(分析命令行参数) getopt(分析命令行参数) 短参数的定义 返回值 范例 getopt_long 相关函数表头文件#include<unistd.h> 函数声明int g ...

  4. [Perl] Getopt 函数来接收用户参数的使用

    我们在linux常常用到一个程序需要加入参数,现在了解一下perl中的有关控制参数的函数.getopt.在linux有的参数有二种形式.一种是–help,另一种是-h.也就是-和–的分别.–表示完整参 ...

  5. [转载]函数getopt(),及其参数optind

    最近用到了getopt()这个函数,对它进行了一些了解.这篇博文还是写的非常清楚的.值得学习.最近在改进一个开源项目,希望自己能静下心好好分析代码. ------------------------- ...

  6. Linux getopt/getopts解析命令行参数教程

    一.说明 shell中获取参数可以直接使用$1.$2等形式来获取,但这种方式有明显的限制:每个参数的位置是固定的.比如如果在设计上$1是ip地址$2是端口,那在执行时就必须第一个参数是ip第二个参数是 ...

  7. getopt_long函数解析命令行参数

    转载:http://blog.csdn.net/hcx25909/article/details/7388750 每一天你都在使用大量的命令行程序,是不是感觉那些命令行参数用起来比较方便,他们都是使用 ...

  8. 使用getopt 解析参数

    getopt被用来解析命令行选项参数. #include <unistd.h> extern char *optarg; //选项的参数指针 extern int optind, //下一 ...

  9. document.execCommand()函数可用参数解析

    隐藏在暗处的方法-execCommand() 关键字: javascript document document.execCommand()方法可用来执行很多我们无法实现的操作. execComman ...

随机推荐

  1. JS编程最佳实践

    最近花了一周时间把<编写可维护的js> 阅读了一遍, 现将全书提到的JS编程最佳实践总结如下, 已追来者! 1.return 之后不可直接换行, 否则会导致ASI(自动分号插入机制)会在r ...

  2. CSS混合模式

    前面的话   层叠上下文z-index只是解决两个元素覆盖,谁离用户更近的问题.而CSS混合模式,则是处理两个元素覆盖部分如何混合的问题.如果了解photoshop的话,对这种现象应该不陌生.CSS3 ...

  3. MVC 视频笔记

    1.关闭Jquery的浏览器缓存 $.ajaxSetup({cache:fasle});

  4. 你应该知道的CSS文字大小单位PX、EM、PT[转]

    摘要: 这里引用的是Jorux的“95%的中国网站需要重写CSS”的文章, 题目有点吓人,但是确实是现在国内网页制作方面的一些缺陷.我一直也搞不清楚px与em之间的关系和特点,看过以后确实收获很大.平 ...

  5. COB(Chip On Board)的製程簡單介紹

    前面提及 COB 的生產與 IC 的封裝製程幾乎是一致的,除了把 leadframe 改成了 PCB,把封膠由 molding 改成 dispensing,少了 triming & marki ...

  6. 在 Inno Setup 中实现倒数N秒后激活按钮

    原文 http://restools.hanzify.org/article.asp?id=67 timectrl.dll 为一个 6.5 KB 的按钮激活时间控制插件.  引用来自 Example1 ...

  7. OMNeT++安装教程

    前提及注意事项: 1) 安装之前首先要确定已经安装好GCC编译环境(例如:MinGW.Cygwin,选择一种安装); (否则OMNeT++会安装不成功),具体安装教程详见另一篇文章 MinGW安装教程 ...

  8. Android学习总结——Broadcast

    一.利用BroadcastReceiever监听短信 AndroidManifest.xml <?xml version="1.0" encoding="utf-8 ...

  9. Server(Iocp)的那些烦恼

    自G-Socket0.88版开源以来,得到很多朋友的支持.从1.0版本至2.0之前,内核几乎没有改变,经过多处的应用其稳定性和效率表现是相当不错的.这几年的经验总结成一句话:服务器程序不是有了一个好的 ...

  10. Object-c学习之路七(oc字符串操作)

    // // main.m // NSString // // Created by WildCat on 13-7-25. // Copyright (c) 2013年 wildcat. All ri ...