最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上。今天听了学长说到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. inflate, findViewById与setContentView的区别与联系

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...

  2. SQL Server 的内存分类

    第一类. 根据申请方式分: commit 型 它是指先reserve申请一大块,再通过commit提交后得到的空间.这种方式申请到的空间可以启用 awe ! stolen型 与commit 相对应!它 ...

  3. Macbook使用技巧

     Mac  OSX下 safari 常用快捷键盘     Command + R  刷新页面     Command + T  新建一个标签      Command + Shift+ 左右方向键   ...

  4. ui的设计原则

    部分网页设计原则 规划目录结构时应当遵循的几个原则: 1.不要将所有文件都存放在根目录下; 2.按栏目内容分别建立子目录; 3.在每个主目录下都建立独立的images目录; 4.目录的层次不要太深; ...

  5. Windows服务程序的原理及实现(服务分为WIN32服务和系统服务)

    今天给大家讲下怎样做一个服务程序...本来是想详细讲的,不过写着写着累得要命..很多 地方就没详细...不过代码我加了点注...如果还有一些不明白的自己查下MSDN......便宜 环境,,VC++6 ...

  6. #include <set>

    1 multiset 多重集合(multiset) 允许存在两个次序相等的元素的集合 <set> 2 set 集合(set) 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作 ...

  7. 全国计算机等级考试二级教程-C语言程序设计_第5章_循环结构

    for循环结构的嵌套 外层循环每循环一次,内层循环会完整循环一次. 外层循环是竖. 内层循环是横. for, do...while, while的选择: 如果有固定次数,如阶乘! ,判断素数,用 fo ...

  8. Windows下安装Python3.4.2

    一.Windows下安装Python3.4.2 1.下载Windows下的Python3.4.2.exe 2.指定一个目录安装,然后下一步 3.配置环境变量包括Python.exe的文件.目录如下图所 ...

  9. UVa 1583 Digit Generator(数学)

     题意 假设a加上a全部数位上的数等于b时 a称为b的generator  求给定数的最小generator 给的数n是小于100,000的  考虑到全部数位和最大的数99,999的数位和也才45 ...

  10. 深入解析CSS样式层叠权重值

    本文为转载内容,源地址:http://www.ofcss.com/2011/05/26/css-cascade-specificity.html 读到<重新认识CSS的权重>这篇,在文章最 ...