函数参数选项的处理getopt getopt_long getopt_long_only
int getopt(int argc,char *argv[], const char *optstring);
extern char *optarg
extern int optind,opterr,optopt;
其中agrc和argv是直接从主函数中传递过来的参数,而optstring是命令选项,命令选项可以是数字或字母,但前面必须有一"-"符号,后面如果有":",则表示该在输入时须带一参数
optarg 当带有选项时,*optarg中保存了参数的字符串
optind 是当前argv的索引值,在调用getopt之后,剩余的选项可以从argv[optind]至argv[argc-1]中提取.
opterr 当此变量非0时,调用getopt()函数在发现选项无效或缺少参数时会打印出出错信息
optopt 在调用getopt()函数发现无效选项或缺少参数时会返回":"字符或"?"字符,并且用optopt保存这个无效的选项(缺少参数返回":",无效选项返回"?")
在调用getopt之前,optind的值为1.当选项不带参数时每调用一次值加1,带参数时加2
Linux程序设计——用getopt处理命令行参数
Linux下很多程序甚至那些具有图形用户界面(graphical user interface,GUI)的程序,都能接受和处理命令行选项。对于某些程序,这是与用户进行交互的主要手段。具有可靠的复杂命令行参数处理机制,会使得您的应用程序更好、更有用。getopt()是一个专门设计来减轻命令行处理负担的库函数。
1、命令行参数
命令行程序设计的首要任务是解析命令行参数,GUI派的程序员很少关心这个。这里,对参数采用了一种比较通俗的定义:命令行上除命令名之外的字符串。参数由多项构成,项与项之间用空白符彼此隔开。
参数进一步分为选项和操作数。选项用于修改程序的默认行为或为程序提供信息,比较老的约定是以短划线开头。选项后可以跟随一些参数,称为选项参数。剩下的就是操作数了。
2、POSIX约定
POSIX表示可移植操作系统接口:Portable Operating System Interface,电气和电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE)最初开发 POSIX 标准,是为了提高 UNIX 环境下应用程序的可移植性。然而,POSIX 并不局限于 UNIX。许多其它的操作系统,例如 DEC OpenVMS 和 Microsoft Windows NT,都支持 POSIX 标准。
程序名应只包含小写字母和阿拉伯数字;
选项名应该是单字符活单数字,且以短横‘-‘为前綴;
多个不需要选项参数的选项,可以合并。(譬如:foo -a -b -c ---->foo -abc)
选项与其参数之间用空白符隔开;
选项参数不可选。
若选项参数有多值,要将其并为一个字串传进来。譬如:myprog -u "arnold,joe,jane"。这种情况下,需要自己解决这些参数的分离问题。
选项应该在操作数出现之前出现。
特殊参数‘--'指明所有参数都结束了,其后任何参数都认为是操作数。
选项如何排列没有什么关系,但对互相排斥的选项,如果一个选项的操作结果覆盖其他选项的操作结果时,最后一个选项起作用;如果选项重复,则顺序处理。
允许操作数的顺序影响程序行为,但需要作文档说明。
读写指定文件的程序应该将单个参数'-'作为有意义的标准输入或输出来对待。
3、GNU长选项
GNU鼓励程序员使用--help、--verbose等形式的长选项。这些选项不仅不与POSIX约定冲突,而且容易记忆,另外也提供了在所有GNU工具之间保持一致性的机会。GNU长选项有自己的约定:
额外针对GNU的长选项不需要对应的短选项,仅仅推荐要有。
长选项可以缩写成保持惟一性的最短的字串。
选项参数与长选项之间或通过空白字符活通过一个'='来分隔。
选项参数是可选的(只对短选项有效)。
长选项允许以一个短横线为前缀。
C程序通过argc和argv参数访问它的命令行参数。argc是整型数,表示参数的个数(包括命令名)。main()函数的定义方式有两种,区别仅在于argv如何定义:
{
……
} int main(int argc, char **argv)
{
……
}
当 C 运行时库的程序启动代码调用 main() 时,已经对命令行进行了处理。argc 参数包含参数的计数值,而 argv 包含指向这些参数的指针数组。argv[0]是程序名。
{
int i, nflg;
if(argc > 1 && argv[1][0] == '-' && argv[1][1] == 'n'){
nflg++;
argc--;
argv++;
}
for(i=1; i<argc; i++){<br=""> fputs(argv[i], stdout);
if(i < argc-1)
putchar(' ');
}
if(nflg == 0)
putchar('\n');
}
getopt()函数声明如下:
extern int optind, opterr, optopt;
int optind——argv的当前索引值。当getopt()在while循环中使用时,循环结束后,剩下的字串视为操作数,在argv[optind]至argv[argc-1]中可以找到。
int opterr——这个变量非零时,getopt()函数为“无效选项”和“缺少参数选项,并输出其错误信息。
以下面的程序为例:
选项:
-g —— 显示“我女朋友的名字”。
-l —— 带参数的选项.
清单2:
#i nclude
#i nclude
{
int oc; /*选项字符 */
char *b_opt_arg; /*选项参数字串 */
{
switch(oc)
{
case 'n':
printf("My name is Lyong.\n");
break;
case 'g':
printf("Her name is Xxiong.\n");
break;
case 'l':
b_opt_arg = optarg;
printf("Our love is %s\n", optarg);
break;
}
}
return 0;
}
My name is Lyong.
$ ./opt_parse_demo -g
Her name is Xxiong.
$ ./opt_parse_demo -l forever
Our love is forever
$ ./opt_parse_demo -ngl forever
My name is Lyong.
Her name is Xxiong.
Our love is forever
不正确的调用程序在所难免,这种错误要么是命令行选项无效,要么是缺少选项参数。正常情况下,getopt()会为这两种情况输出自己的出错信息,并且返回'?'。为了验证此事,可以修改一下上面的清单2中的代码。
#i nclude
{
int oc; /*选项字符 */
char *b_opt_arg; /*选项参数字串 */
{
switch(oc)
{
case 'n':
printf("My name is Lyong.\n");
break;
case 'g':
printf("Her name is Xxiong.\n");
break;
case 'l':
b_opt_arg = optarg;
printf("Our love is %s\n", optarg);
break;
case '?':
printf("arguments error!\n");
break;
}
}
return 0;
}
./opt_parse_demo: option requires an argument -- l
arguments error!
在调用getopt()之前,将opterr设置为0,这样就可以在getopt()函数发现错误的时候强制它不输出任何消息。
如果optstring参数的第一个字符是冒号,那么getopt()函数就会保持沉默,并根据错误情况返回不同字符,如下:
“无效选项” —— getopt()返回'?',并且optopt包含了无效选项字符(这是正常的行为)。
“缺少选项参数” —— getopt()返回':',如果optstring的第一个字符不是冒号,那么getopt()返回'?',这会使得这种情况不能与无效选项的情况区分开。
清单4:
#i nclude
#i nclude
{
int oc; /*选项字符 */
char ec; /*无效的选项字符*/
char *b_opt_arg; /*选项参数字串 */
{
switch(oc)
{
case 'n':
printf("My name is Lyong.\n");
break;
case 'g':
printf("Her name is Xxiong.\n");
break;
case 'l':
b_opt_arg = optarg;
printf("Our love is %s\n", optarg);
break;
case '?':
ec = (char)optopt;
printf("无效的选项字符 \' %c \'!\n", ec);
break;
case ':':
printf("缺少选项参数!\n");
break;
}
}
return 0;
}
无效的选项字符 ' a '!
$ ./opt_parse_demo -l
缺少选项参数!
上面所设计的getopt()函数是UNIX支持小组提供的,其执行时一碰到不以'-'开始的命令行参数就停止寻找选项。而GNU提供的getopt()函数与之不同,它会扫描整个命令行来寻找选项。当调用GNU getopt()函数并处理命令行参数的时候,它重新排列argv中的元素,这样当重排结束时,所有选项都被移动到前面并且那些继续检查argv[optind]至argv[argc-1]中剩余参数的代码仍正常工作,但在任何情况下,碰到特殊参数'--'就结束对选项的扫描。
Our love is forever
Her name is Xxiong.
My name is Lyong.
optstring[0] = '-',会在optarg中得到命令行中的每个参数。
以上两种情况下,':'可以作为第二个字符使用。
GNU getopt()第三个特点是optstring中的选项字符后面接两个冒号,就允许该选项有可选的选项参数。在选项参数不存在的情况下,GNU getopt()返回选项字符并将optarg设置为NULL。
20 世纪 90 年代,UNIX 应用程序开始支持长选项,即一对短横线、一个描述性选项名称,还可以包含一个使用等号连接到选项的参数。
getopt_long() 是同时支持长选项和短选项的 getopt() 版本。下面是它们的声明:
const char *name;
int has_arg;
int *flag;
int val;
};
这是选项名,前面没有短横线。譬如"help"、"verbose"之类。
描述了选项是否有选项参数。如果有,是哪种类型的参数,此时,它的值一定是下表中的一个。
no_argument 0 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数可选
如果这个指针为NULL,那么getopt_long()返回该结构val字段中的数值。如果该指针不为NULL,getopt_long()会使得它所指向的变量中填入val字段中的数值,并且getopt_long()返回0。如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变。对应最后那个程序为什么flag设为NULL就可以了。
这个值是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值。典型情况下,若flag不是NULL,那么val是个真/假值,譬如1或0;另一方面,如果flag是NULL,那么val通常是字符常量,若长选项与短选项一致,那么该字符常量应该与optstring中出现的这个选项的参数相同。
char *b_opt_arg;
{
switch (c){
case 'n':
do_name = 1;
case 'g':
do_gf_name = 1;
break;
break;
case 'l':
b_opt_arg = optarg;
……
}
}
#i nclude
char *l_opt_arg;
{ "name", no_argument, &do_name, 1 },
{ "gf_name", no_argument, &do_gf_name, 1 },
{ "love", required_argument, NULL, 'l' },
{ 0, 0, 0, 0},
};
{
int c;
while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){
switch (c){
case 'l':
l_opt_arg = optarg;
printf("Our love is %s!\n", l_opt_arg);
break;
case 0:
printf("getopt_long()设置变量 : do_name = %d\n", do_name);
printf("getopt_long()设置变量 : do_gf_name = %d\n", do_gf_name);
break;
}
}
return 0;
}
getopt_long()设置变量 : do_name = 1
getopt_long()设置变量 : do_gf_name = 0
getopt_long()设置变量 : do_name = 0
getopt_long()设置变量 : do_gf_name = 1
Our love is forever!
Our love is forever!
含 义
0
getopt_long()设置一个标志,它的值与option结构中的val字段的值一样
1
每碰到一个命令行参数,optarg都会记录它
'?'
无效选项
':'
缺少选项参数
'x'
选项字符'x'
-1
选项解析结束
#i nclude
#i nclude
char *l_opt_arg;
{ "name", no_argument, NULL, 'n' },
{ "gf_name", no_argument, NULL, 'g' },
{ "love", required_argument, NULL, 'l' },
{ 0, 0, 0, 0},
};
{
int c;
while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1){
switch (c){
case 'n':
printf("My name is LYR.\n");
break;
case 'g':
printf("Her name is BX.\n");
break;
case 'l':
l_opt_arg = optarg;
printf("Our love is %s!\n", l_opt_arg);
break;
}
}
return 0;
}
$ ./long_opt_demo --name --gf_name --love forever
My name is LYR.
Her name is BX.
Our love is forever!
My name is LYR.
Her name is BX.
Our love is forever!
只要从GNU程序或GNU C Library(GLIBC)的CVS档案文件中copy源文件即可(http://sourceware.org/glibc/)。所需源文件是getopt.h、getopt.c和getoptl.c,将这些文件包含在你的项目中。另外,你的项目中最好也将COPYING.LIB文件包含进去,因为GNU LGPL(GNU 程序库公共许可证)的内容全部包括在命名为COPYING.LIB 的文件中。
10、结论
函数参数选项的处理getopt getopt_long getopt_long_only的更多相关文章
- 命令行參数选项处理:getopt()及getopt_long()函数使用
在执行某个程序的时候,我们通常使用命令行參数来进行配置其行为.命令行选项和參数控制 UNIX 程序,告知它们怎样动作. 当 gcc的程序启动代码调用我们的入口函数 main(int argc ...
- 命令行参数解析:getopt,getopt_long
#include <unistd.h> int getopt(int argc, char * const argv[], const char *optstring); extern c ...
- apue编程之getopt ,getopt_long使用方法以及实例
1.getopt 1.1 函数定义 int getopt(int argc, char * const argv[], const char *optstring);#include <unis ...
- C语言命令行解析函数:getopt/getopt_long
命令行工具下的参数选项有两种,长选项和短选项.短选项以-开头,后面跟单个字母:长选项以--开头,后面可跟多个字母. 一. getopt() 1.功能:解析命令行短选项参数 2.函数原型: #inclu ...
- 命令行解析函数:getopt/getopt_long
参考: http://blog.csdn.net/zhangyang0402/article/details/5671410 http://www.cnblogs.com/gnuhpc/archive ...
- 你好,C++(26)如何与函数内部进行数据交换?5.1.3 函数参数的传递
5.1.3 函数参数的传递 我们知道,函数是用来完成某个功能的相对独立的一段代码.函数在完成这个功能的时候,往往需要外部数据的支持,这时就需要在调用这个函数时向它传递所需要的数据它才能完成这个功能获 ...
- 关于python 函数参数
函数参数:必选参数.默认参数.可选参数.关键字参数 1.默认参数 默认参数可以简化函数的调用.设置默认参数时,有几点要注意: 一是必选参数在前,默认参数在后,否则Python的解释器会报错: 二是如何 ...
- TensorFlow卷积网络常用函数参数详细总结
卷积操作 tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None) 除去name参数用以指定该操作 ...
- Eigen使用矩阵作为函数参数
1 使用矩阵作为函数参数介绍 文章来源Writing Functions Taking %Eigen Types as Parameters Eigen为了在函数中传递不同的类型使用了表达式模板技术. ...
随机推荐
- 使用MSSQL,连接oracle,对oracle数据进行操作
EXEC sp_addlinkedserver--创建链接服务器.链接服务器让用户可以对 OLE DB 数据源进行分布式异类查询. @server = 'Mktg',--要创建的链接服务器的名称.s ...
- 使用dbcp : BasicDataSource
需要 commons-dbcp2 com.oracle.ojdbc6 <dependency> <groupId>org.apache.commons</groupId& ...
- GC:垃圾回收器简介
Java堆内存被划分为新生代和年老代两部分,新生代主要使用复制和标记-清除垃圾回收算法,年老代主要使用标记-整理垃圾回收算法,因此java虚拟中针对新生代和年老代分别提供了多种不同的垃圾收集器,JDK ...
- So many good projects for studying C programming lanuage.
Some one asked a question for studying C programming language on stackexachange.com. He got a bucket ...
- 当WEB站点应用程序池标识为ApplicationPoolIdentity,出现运行错误时的解决方法
对于数据库文件加Authenticated Users用户,并授予完全权限.
- 无责任Windows Azure SDK .NET开发入门篇三[使用Azure AD 管理用户信息--3.4 Edit修改用户信息]
3.4 Edit修改用户信息 我们用FormCollection简化了表单提交,非常方便的进行用户信息修改. [HttpPost, Authorize] public async Task<Ac ...
- web APi角色认证
http://www.cnblogs.com/youring2/archive/2013/03/09/2950992.html http://kb.cnblogs.com/page/107117/
- Android 通过xml 自定义图片
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http:/ ...
- Flex编程注意之直接获取某个组件的对象(this[]用法)通过id获取控件
有这样一个需求:假如你new了一百次Button,同时这些button的id分别赋值如btn1.id = "button1"; btn2.id = "button2&qu ...
- Oracle 数据文件管理
1.手工改变数据文件的大小 SQL>conn / as sysdba SQL>Createtablespace exampletb Datafile 'E:\ examp01.dbf' s ...