最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上。今天听了学长说到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. win7+IE11 中开发工具报错occurredJSLugin.3005解决办法

    系统环境 win7+IE11 报错描述: Exception in window.onload: Error: An error has ocurredJSPlugin.3005 Stack Trac ...

  2. 2015.4.7-C#入门基础(一)

    一. .net framework 的特点 1.两个主要组件 1> CLR 表示运行时的环境,同时也保证了.net 中的一种一种语言具有的功能其他语言也都具有: 2> 统一的类库集 2.M ...

  3. HTML5 canvas 在线画笔绘图工具(三)

    组装画板(TDrawBuilder) 在这一小节中我们要把工具条和画板组装起来,让他们可以协同进行工作. 画板通过一个命名为TDrawBuilder来进行组装.在详细讲解TDrawBuilder对象之 ...

  4. Oracle EBS-SQL (BOM-17):检查8层BOM.sql

    define item1="1234567890" select a1.产品编码, a1.产品描述, '1层'         层数, a1.物料编码, a1.物料描述, a1.单 ...

  5. HeadFirst设计模式读书笔记(5)-单例模式

    单例模式:确保一个类只有一个实例,并提供一个全局访问点. 应用场景:数据库连接.线程池.缓存.对话框.处理偏好设置.注册表的对象.日志对象.充当打印机.显卡等设备的驱动程序对象.任务管理器.网站的计数 ...

  6. 100个linux常用命令

    1,echo “aa” > test.txt 和 echo “bb” >> test.txt //>将原文件清空,并且内容写入到文件中,>>将内容放到文件的尾部 2 ...

  7. 关于URL编码的问题

    在进行WEB开发时,字符集编码常常困扰着我们.我们需要区分两种情况,一是URL编码,二是HTTP Body编码.这两种编码所处理的机制不同. URL编码和解码 客户端负责对URL编码,服务端负责解码. ...

  8. [Leetcode][Python]41: First Missing Positive

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 41: First Missing Positivehttps://oj.le ...

  9. flume【源码分析】分析Flume的拦截器

    h2 { color: #fff; background-color: #7CCD7C; padding: 3px; margin: 10px 0px } h3 { color: #fff; back ...

  10. mysql 1449 : The user specified as a definer ('montor'@'%') does not exist

    grant all privileges on *.* to root@"%" identified by "."; flush privileges;