最近在写程序的过程中,把一部分时间都花费在程序对参数的处理上。今天听了学长说到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手册

  1. man getopt

getopt的函数原型如下:

  1. #include <unistd.h>
  2. int getopt(int argc, char * const argv[], const char *optstring);
  3.  
  4. extern char *optarg;
  5. 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完美实现这一点。

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

  1. typedef struct parameter
  2. {
  3. int a; //参数a
  4. int b; //参数b
  5. char *b_pri; //参数b的关联值
  6. int c; //参数c
  7. char *c_pri; //参数c的关联值
  8. }par;

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

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

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

  1. //参数初始化
  2. opt.a = ;
  3. opt.b = ;
  4. opt.b_pri = NULL;
  5. opt.c = ;
  6. opt.c_pri = NULL;

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

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4.  
  5. typedef struct parameter
  6. {
  7. int a; //参数a
  8. int b; //参数b
  9. char *b_pri; //参数b的关联值
  10. int c; //参数c
  11. char *c_pri; //参数c的关联值
  12. }par;
  13.  
  14. int main( int argc, char **argv )
  15. {
  16. int i; //循环变量
  17. par opt; //参数
  18. int flag = ; //循环退出标志位
  19.  
  20. //参数初始化
  21. opt.a = ;
  22. opt.b = ;
  23. opt.b_pri = NULL;
  24. opt.c = ;
  25. opt.c_pri = NULL;
  26.  
  27. //参数检测
  28. if (argc == )
  29. {
  30. printf("您没有设置选项!\n");
  31. exit();
  32.  
  33. }
  34. //输出未处理的参数
  35. printf("系统传入的参数为:");
  36. for ( i = ; i < argc; i++)
  37. {
  38. printf("%s ",argv[i]);
  39. }
  40. printf("\n");
  41.  
  42. //循环处理传入参数
  43. while(flag != -)
  44. {
  45. //调用getopt处理参数
  46. switch(getopt( argc, argv, "ab:c::?"))
  47. {
  48. case 'a':
  49. opt.a = ;
  50. break;
  51. case 'b':
  52. opt.b = ;
  53. opt.b_pri = optarg;
  54. break;
  55. case 'c':
  56. opt.c = ;
  57. opt.c_pri = optarg;
  58. break;
  59. case -:
  60. flag = -;
  61. break;
  62. default:
  63. break;
  64. }
  65. }
  66.  
  67. if( optind != argc)
  68. {
  69. printf("参数中非程序选项的有:");
  70. for (i = optind; i < argc; i++)
  71. {
  72. printf("%s\t",argv[i]);
  73. }
  74. printf("\n");
  75. }
  76.  
  77. //输出解析结果
  78. printf("解析到程序启动后启用的选项有:");
  79. if (opt.a == )
  80. printf("a,");
  81. if (opt.b == )
  82. printf("b(参数为:%s),",opt.b_pri);
  83. if (opt.c == )
  84. printf("c(参数为:%s),",opt.c_pri);
  85. printf("\n");
  86.  
  87. //处理后,输出全部参数与原来对比
  88. printf("使用getopt后,系统参数变为为:");
  89. for ( i = ; i < argc; i++)
  90. {
  91. printf("%s ",argv[i]);
  92. }
  93. printf("\n");
  94.  
  95. return ;
  96. }

保存后,编译运行。

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

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

  1. opterr = ;
  2.  
  3. static const char *optstring = "ab:c::";

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

  1. opterr = ; //getopt不输出错误参数
  2.  
  3. ...其他程序段...
  4.  
  5. //循环处理传入参数
  6. while(flag != -)
  7. {
  8. //调用getopt处理参数
  9. switch(getopt( argc, argv, "ab:c::"))
  10. {
  11. case 'a':
  12. opt.a = ;
  13. break;
  14. case 'b':
  15. opt.b = ;
  16. opt.b_pri = optarg;
  17. break;
  18. case 'c':
  19. opt.c = ;
  20. opt.c_pri = optarg;
  21. break;
  22. case '?':
  23. printf("出现非正常选项:%c\n",optopt);
  24. break;
  25. case -:
  26. flag = -;
  27. break;
  28. default:
  29. break;
  30. }
  31. }

程序源代码如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4.  
  5. typedef struct parameter
  6. {
  7. int a; //参数a
  8. int b; //参数b
  9. char *b_pri; //参数b的关联值
  10. int c; //参数c
  11. char *c_pri; //参数c的关联值
  12. }par;
  13.  
  14. int main( int argc, char **argv )
  15. {
  16. int i; //循环变量
  17. par opt; //参数
  18. int flag = ; //循环退出标志位
  19.  
  20. //参数初始化
  21. opt.a = ;
  22. opt.b = ;
  23. opt.b_pri = NULL;
  24. opt.c = ;
  25. opt.c_pri = NULL;
  26. opterr = ; //getopt不输出错误参数
  27.  
  28. //参数检测
  29. if (argc == )
  30. {
  31. printf("您没有设置选项!\n");
  32. exit();
  33.  
  34. }
  35. //输出未处理的参数
  36. printf("系统传入的参数为:");
  37. for ( i = ; i < argc; i++)
  38. {
  39. printf("%s ",argv[i]);
  40. }
  41. printf("\n");
  42.  
  43. //循环处理传入参数
  44. while(flag != -)
  45. {
  46. //调用getopt处理参数
  47. switch(getopt( argc, argv, "ab:c::"))
  48. {
  49. case 'a':
  50. opt.a = ;
  51. break;
  52. case 'b':
  53. opt.b = ;
  54. opt.b_pri = optarg;
  55. break;
  56. case 'c':
  57. opt.c = ;
  58. opt.c_pri = optarg;
  59. break;
  60. case '?':
  61. printf("出现非正常选项:%c\n",optopt);
  62. break;
  63. case -:
  64. flag = -;
  65. break;
  66. default:
  67. break;
  68. }
  69. }
  70.  
  71. if( optind != argc)
  72. {
  73. printf("参数中非程序选项的有:");
  74. for (i = optind; i < argc; i++)
  75. {
  76. printf("%s\t",argv[i]);
  77. }
  78. printf("\n");
  79. }
  80.  
  81. //输出解析结果
  82. printf("解析到程序启动后启用的选项有:");
  83. if (opt.a == )
  84. printf("a,");
  85. if (opt.b == )
  86. printf("b(参数为:%s),",opt.b_pri);
  87. if (opt.c == )
  88. printf("c(参数为:%s),",opt.c_pri);
  89. printf("\n");
  90.  
  91. //处理后,输出全部参数与原来对比
  92. printf("使用getopt后,系统参数变为为:");
  93. for ( i = ; i < argc; i++)
  94. {
  95. printf("%s ",argv[i]);
  96. }
  97. printf("\n");
  98.  
  99. return ;
  100. }

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

  1. $ ./a.out -a -b -h -c1
  2. 系统传入的参数为:-a -b -h -c1
  3. 出现非正常选项:h
  4. 参数中非程序选项的有:
  5. 解析到程序启动后启用的选项有:a,b(参数为:),c(参数为:),
  6. 使用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. E - Number Sequence(第二季水)

    Description A single positive integer i is given. Write a program to find the digit located in the p ...

  2. python文件处理及装饰器

    1.文件处理: Python处理文件的流程比较简单,大致分为以下几个: 打开文件==>处理文件==>生成新文件==>写入文件 先说怎么打开一个文件: 打开一个文件可以有多种写法,下面 ...

  3. Python学习笔记(五)Python的切片和迭代

    切片 Python提供了切片操作符,可以对list.tuple.字符串进行截取操作. list中的切片应用 语法如下: >>> L = ['Michael', 'Sarah', 'T ...

  4. poj2301

    Beat the Spread! Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17794   Accepted: 8484 ...

  5. C Statements

    1,while((ch = getchar()) != EOF){    putchar(ch);}2,while((ch=getchar()) != EOF){    if(ch < '0' ...

  6. java反射 实例

    首先介绍几个概念: 1.Java反射的概念 反射含义:可以获取正在运行的Java对象. 2.Java反射的功能 1)可以判断运行时对象所属的类 2)可以判断运行时对象所具有的成员变量和方法 3)通过反 ...

  7. HDU 1852 Beijing 2008 数论

    题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1852 这道题和HDU1452类似. 题意:给你一个n.k,让你求2008^n所有因子的和(包括1和本 ...

  8. curl+个人证书(又叫客户端证书)访问https站点

    摘自http://blog.csdn.net/chary8088/article/details/22990741 curl+个人证书(又叫客户端证书)访问https站点 目前,大公司的OA管理系统( ...

  9. 网易云课堂_C++程序设计入门(上)_第2单元:丹青画松石– EGE图形库

    第2节:一个简单的EGE程序 #ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ #ifndef __cplusplus #error You must use C++ ...

  10. Js节点属性与方法

    属性: Attributes     存储节点的属性列表(只读) childNodes 存储节点的子节点列表(只读) dataType     返回此节点的数据类型 Definition     以D ...