最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上。今天听了学长说到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. [Effective Modern C++] Item 6. Use the explicitly typed initializer idiom when auto deduces undesired types - 当推断意外类型时使用显式的类型初始化语句

    条款6 当推断意外类型时使用显式的类型初始化语句 基础知识 当使用std::vector<bool>的时候,类型推断会出现问题: std::vector<bool> featu ...

  2. CentOS minimal版安装图形界面的步骤(自动获取IP)

    1.连接网络: CentOS minimal.iso安装好后,进入终端,默认是不开网络的, 首先启用网卡, 自动获取ip. ifconfig eth0 up   www.2cto.com  dhcli ...

  3. 接口(三)——JAVA的多重继承

    一.接口的作用 ①.为了能够向上转型为多个基类型 ②.防止客户端程序员创建该类的对象——同抽象类 二.通过继承扩展接口 interface Monster{ void menace(); } inte ...

  4. Python成长之路第二篇(2)_列表元组内置函数用法

    列表元组内置函数用法list 元组的用法和列表相似就不一一介绍了 1)def append(self, p_object):将值添加到列表的最后 # real signature unknown; r ...

  5. lol.py

    #!/usr/bin/env python # -*- coding: utf-8 -*- import os from twisted.application import service from ...

  6. python学习之day13

    目录 JavaScript Dom jQuery   JavaScript JavaScript 是世界上最流行的编程语言. 这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑 ...

  7. Oracle EBS-SQL (BOM-18):检查BOM与工艺路线对照.sql

    /*有工艺路线,无BOM清单*/ select msi.segment1, msi.description from apps.BOM_OPERATIONAL_ROUTINGS bor, apps.m ...

  8. Eclipse的NDEF插件诞生,将加速NFC应用开发

    今年2月份,NFC论坛刚刚发布了NFC技术的首个规范NDEF(nfc data exchange format)-即NFC数据交换规范.而不到2个月的今天Eclipse就发布了基于NDEF规范的NFC ...

  9. aliyun.com

    https://help.aliyun.com/knowledge_detail/39495.html?spm=5176.7839494.2.1.AhdvPM

  10. 【D3.V3.js系列教程】--(十四)有路径的文字

    [D3.V3.js系列教程]--(十四)有路径的文字 1. 在 svg 中插入一個 text // 在 body 中插入一個 svg var svg = d3.select('body').appen ...