一、简介

getopt()函数是一个标准库调用,可允许您使用直接的 while/switch 语句方便地逐个处理命令行参数和检测选项(带或不带附加的参数)。与其类似的getopt_long()允许在几乎不进行额外工作的情况下处理更具描述性的长选项,这非常受开发人员的欢迎。

二、示例

1、getopt()
函数原型

getopt(int argc,char *const argv[],const char *optstring)

参数说明

argc和argv一般就将main函数的那两个参数原样传入。
optstring是一段自己规定的选项串,“:”表示该选项必须带有额外的参数,全域变量optarg会指向此额外参数,“::”标识该额外的参数可选(带的额外参数必须紧挨着该选项,有些Uinx可能不支持“::”)
全域变量optind指示下一个要读取的参数在argv中的位置。如果getopt()找不到符合的参数则会印出错信息,并将全域变量optopt设为“?”字符。如果不希望getopt()印出错信息,则只要将全域变量opterr设为0即可。

使用示例

#include <stdio.h>
#include <unistd.h> int main(int argc,char *argv[])
{
int ch;
opterr=0; while((ch=getopt(argc,argv,"a:b::cde"))!=-1)
{
printf("optind:%d\n",optind);
printf("optarg:%s\n",optarg);
printf("ch:%c\n",ch);
switch(ch)
{
case 'a':
printf("option a:'%s'\n",optarg);
break;
case 'b':
printf("option b:'%s'\n",optarg);
break;
case 'c':
printf("option c\n");
break;
case 'd':
printf("option d\n");
break;
case 'e':
printf("option e\n");
break;
default:
printf("other option:%c\n",ch);
}
printf("optopt+%c\n",optopt);
}
}

运行

2、getopt_long()

函数原型

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex)

参数说明

函数中的argc和argv通常直接从main()的两个参数传递而来。optsting是选项参数组成的字符串:

字符串optstring可以下列元素:

    1.单个字符,表示选项,

     2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。

     3.单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。

参数longopts,其实是一个结构的实例:

    struct option 
   {
const char *name;//name表示的是长参数名
int has_arg; //has_arg有3个值,no_argument(或者是0),表示该参数后面不跟参数值
// required_argument(或者是1),表示该参数后面一定要跟个参数值
// optional_argument(或者是2),表示该参数后面可以跟,也可以不跟参数值
int *flag; //用来决定,getopt_long()的返回值到底是什么。如果flag是null(通常情况),则函数会返回与该项option匹配的val值;
                        //如果flag不是NULL,则将val值赋予flag所指向的内存,并且返回值设置为0
        int val;         //和flag联合决定返回值
} 参数longindex,表示当前长参数在longopts中的索引值

使用示例

#include <stdio.h>
#include <getopt.h> int do_name, do_gf_name;
char *l_opt_arg; struct option longopts[] =
{
{ "name", no_argument, NULL, 'n'},
{ "gf_name", no_argument, NULL, 'g'},
{ "love", required_argument, NULL, 'l'},
{ 0, 0, 0, 0},
}; int main(int argc, char *argv[])
{
int c; while((c = getopt_long(argc, argv, ":l:", longopts, NULL)) != -1)
{
switch (c)
{
case 'n':
printf("My name is Jay.\n");
break;
case 'g':
printf("Her name is Afra.\n");
break;
case 'l':
l_opt_arg = optarg;
printf("Our love is %s!\n", l_opt_arg);
break;
}
}
return 0;
}

运行

3、使用 gperf实现高效的C/C++ 命令行处理

三、Apache 命令行处理分析

Apache通过apr_getopt_init函数对命令行结构opt进行初始化

apr_getopt_init(&opt, pcommands, process->argc, process->argv);

apr_getopt_init函数实现在文件:srclib\apr\misc\unix\getopt.c,代码如下:

APR_DECLARE(apr_status_t) apr_getopt_init(apr_getopt_t **os, apr_pool_t *cont, int argc, const char *const *argv)
{
void *argv_buff; *os = apr_palloc(cont, sizeof(apr_getopt_t));
(*os)->cont = cont;
(*os)->reset = 0;
(*os)->errfn = (apr_getopt_err_fn_t*)(fprintf);
(*os)->errarg = (void*)(stderr); (*os)->place = EMSG;
(*os)->argc = argc; /* The argv parameter must be compatible with main()'s argv, since
that's the primary purpose of this function. But people might
want to use this function with arrays other than the main argv,
and we shouldn't touch the caller's data. So we copy. */
argv_buff = apr_palloc(cont, (argc + 1) * sizeof(const char *));
memcpy(argv_buff, argv, argc * sizeof(const char *));
(*os)->argv = argv_buff;
(*os)->argv[argc] = NULL; (*os)->interleave = 0;
(*os)->ind = 1;
(*os)->skip_start = 1;
(*os)->skip_end = 1; return APR_SUCCESS;
}

而后调用apr_getopt(opt, AP_SERVER_BASEARGS, &c, &optarg)进行命令行解析处理,代码如下

while ((rv = apr_getopt(opt, AP_SERVER_BASEARGS, &c, &optarg)) == APR_SUCCESS) 
{
char **new; switch (c) {
case 'c':
new = (char **)apr_array_push(ap_server_post_read_config);
*new = apr_pstrdup(pcommands, optarg);
break; case 'C':
new = (char **)apr_array_push(ap_server_pre_read_config);
*new = apr_pstrdup(pcommands, optarg);
break; case 'd':
def_server_root = optarg;
break; case 'D':
new = (char **)apr_array_push(ap_server_config_defines);
*new = apr_pstrdup(pcommands, optarg);
/* Setting -D DUMP_VHOSTS is equivalent to setting -S */
if (strcmp(optarg, "DUMP_VHOSTS") == 0)
configtestonly = 1;
/* Setting -D DUMP_MODULES is equivalent to setting -M */
if (strcmp(optarg, "DUMP_MODULES") == 0)
configtestonly = 1;
break; case 'e':
if (strcasecmp(optarg, "emerg") == 0) {
ap_default_loglevel = APLOG_EMERG;
}
else if (strcasecmp(optarg, "alert") == 0) {
ap_default_loglevel = APLOG_ALERT;
}
else if (strcasecmp(optarg, "crit") == 0) {
ap_default_loglevel = APLOG_CRIT;
}
else if (strncasecmp(optarg, "err", 3) == 0) {
ap_default_loglevel = APLOG_ERR;
}
else if (strncasecmp(optarg, "warn", 4) == 0) {
ap_default_loglevel = APLOG_WARNING;
}
else if (strcasecmp(optarg, "notice") == 0) {
ap_default_loglevel = APLOG_NOTICE;
}
else if (strcasecmp(optarg, "info") == 0) {
ap_default_loglevel = APLOG_INFO;
}
else if (strcasecmp(optarg, "debug") == 0) {
ap_default_loglevel = APLOG_DEBUG;
}
else {
usage(process);
}
break; case 'E':
temp_error_log = apr_pstrdup(process->pool, optarg);
break; case 'X':
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DEBUG";
break; case 'f':
confname = optarg;
break; case 'v':
printf("Server version: %s\n", ap_get_server_description());
printf("Server built: %s\n", ap_get_server_built());
destroy_and_exit_process(process, 0); case 'V':
show_compile_settings();
destroy_and_exit_process(process, 0); case 'l':
ap_show_modules();
destroy_and_exit_process(process, 0); case 'L':
ap_show_directives();
destroy_and_exit_process(process, 0); case 't':
configtestonly = 1;
break; case 'S':
configtestonly = 1;
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DUMP_VHOSTS";
break; case 'M':
configtestonly = 1;
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DUMP_MODULES";
break; case 'h':
case '?':
usage(process);
}
} /* bad cmdline option? then we die */
if (rv != APR_EOF || opt->ind < opt->argc) {
usage(process);
}

apr_getopt函数实现在文件:srclib\apr\misc\unix\getopt.c,逻辑如下:

1、进行(os->reset || !*os->place)判断,作用未知

2、通过strchr(opts, os->opt)判断选项(os->opt)是否合法

3、若选项合法,则通过(*++oli != ':')判断该选项是否需要额外参数

4、若需要额外参数,则通过optch、optarg返回解析结果

APR_DECLARE(apr_status_t) apr_getopt(apr_getopt_t *os, const char *opts, char *optch, const char **optarg)
{
const char *oli; /* option letter list index */ if (os->reset || !*os->place) { /* update scanning pointer */
os->reset = 0;
if (os->ind >= os->argc || *(os->place = os->argv[os->ind]) != '-') {
os->place = EMSG;
*optch = os->opt;
return (APR_EOF);
}
if (os->place[1] && *++os->place == '-') { /* found "--" */
++os->ind;
os->place = EMSG;
*optch = os->opt;
return (APR_EOF);
}
} /* option letter okay? */
if ((os->opt = (int) *os->place++) == (int) ':' ||
!(oli = strchr(opts, os->opt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (os->opt == (int) '-') {
*optch = os->opt;
return (APR_EOF);
}
if (!*os->place)
++os->ind;
if (os->errfn && *opts != ':') {
(os->errfn)(os->errarg, "%s: illegal option -- %c\n",
apr_filepath_name_get(*os->argv), os->opt);
}
*optch = os->opt;
return (APR_BADCH);
}
if (*++oli != ':') { /* don't need argument */
*optarg = NULL;
if (!*os->place)
++os->ind;
}
else { /* need an argument */
if (*os->place) /* no white space */
*optarg = os->place;
else if (os->argc <= ++os->ind) { /* no arg */
os->place = EMSG;
if (*opts == ':') {
*optch = os->opt;
return (APR_BADARG);
}
if (os->errfn) {
(os->errfn)(os->errarg,
"%s: option requires an argument -- %c\n",
apr_filepath_name_get(*os->argv), os->opt);
}
*optch = os->opt;
return (APR_BADCH);
}
else /* white space */
*optarg = os->argv[os->ind];
os->place = EMSG;
++os->ind;
}
*optch = os->opt;
return APR_SUCCESS;
}

C语言命令行处理的更多相关文章

  1. 【嵌入式开发】C语言 命令行参数 函数指针 gdb调试

    . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshul ...

  2. C语言 命令行参数 函数指针 gdb调试

    . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshul ...

  3. Go语言命令行操作命令详细介绍

    转自:http://www.jb51.net/article/56781.htm Go 命令 Go语言自带有一套完整的命令操作工具,你可以通过在命令行中执行go来查看它们: 图 Go命令显示详细的信息 ...

  4. c语言命令行参数

    int main(int argc, char * argv[]) { ..... } argc: 代表启动程序时,命令行参数的个数.C和C++语言规定,可执行程序程序本身的文件名,也算是一个命令行参 ...

  5. Go语言 命令行解析(一)

    命令行启动服务的方式,在后端使用非常广泛,如果有写过C语言的同学相信不难理解这一点!在C语言中,我们可以根据argc和argv来获取和解析命令行的参数,从而通过不同的参数调取不同的方法,同时也可以用U ...

  6. C语言命令行解析函数:getopt/getopt_long

    命令行工具下的参数选项有两种,长选项和短选项.短选项以-开头,后面跟单个字母:长选项以--开头,后面可跟多个字母. 一. getopt() 1.功能:解析命令行短选项参数 2.函数原型: #inclu ...

  7. 关于C语言命令行参数问题

    1 int main(int argc,char** argv) 参数: argc:命令行参数的个数 argv:保存命令行参数:argv[0]保存本程序自己的名称 现在自己只知道这些以后再有学习继续补 ...

  8. R 语言命令行参数处理

    在unix.windows外部需要调用R脚本执行,然后又需要输入不同的参数,类似shell脚本的命令行参数输入,可以使用Rcript命令实现. 命令格式:Rscript [options] [-e e ...

  9. R语言命令行参数

        批量画图任务中,需要在R中传入若干参数,之前对做法是在perl中每一个任务建立一个Rscript,这种方式超级不cool,在群里学习到R的@ARGV调用方式,差不多能够达到批量任务的要求: a ...

随机推荐

  1. python静态方法类方法属性方法

    Python的静态方法和类成员方法都可以被类或实例访问,两者概念不容易理清,但还是有区别的: 1)静态方法无需传入self参数,类成员方法需传入代表本类的cls参数: 2)从第1条,静态方法是无法访问 ...

  2. test20181024 nan

    题意 nan 问题描述 我们有一个序列,现在他里面有三个数1,2,2.我们从第三个数开始考虑: 第三个数是2,所以我们在序列后面写2个3,变成1,2,2,3,3. 第四个数是3,所以我们在序列后面写3 ...

  3. test20181019 B君的第三题

    题意 B 君的第三题(urumqi) 题目描述 风雨如晦,鸡鸣不已. B 君最近在研究自己的学长都在做什么工作,每个学长属于一个公司. B 君会获得一些信息,比如x 和y 在相同公司,x 和y 在不同 ...

  4. 几种Python执行时间的计算方法

    究竟是使用 time.clock() 精度高,还是使用 time.time() 精度更高,要视乎所在的平台来决定.总概来讲,在 Unix 系统中,建议使用 time.time(),在 Windows ...

  5. python eval, exec. compile

    compile 编译某段代码, (将一个字符串编译为字节代码), 以方便重复调用. exec 可以理解为和if, for一样是一个语法声明, 而不是一个函数. 注意globals和locals的含义. ...

  6. 在WPF中使用CefSharp嵌入浏览器(转)

    在WPF中使用CefSharp嵌入浏览器   日常开发中,我们需要将一些Web页面嵌入到桌面客户端软件中.下面我们使用CefSharp嵌入浏览器来实现. 首先先介绍一下CefSharp嵌入式浏览器,它 ...

  7. java程序运行时内存分配详解

    java程序运行时内存分配详解 这篇文章主要介绍了java程序运行时内存分配详解 ,需要的朋友可以参考下   一. 基本概念 每运行一个java程序会产生一个java进程,每个java进程可能包含一个 ...

  8. spring与hibernate注解及XML方式集成

    spring与hibernate注解及XML方式集成 Hibernate Xml方式 该种方式需要在sessionFactory中引入对应的hbm.xml文件,样例如下: <!-- spring ...

  9. 转转转--oracle 去重并按时间排序取第一条

    select t.* from (select a.*, row_number() over(partition by 需要分组的字段 order by 更新时间 desc) rw from 表 a) ...

  10. postman-3断言

    用例3A原则: arrange:初始化测试对象 act:操作.接口测试中通过不同的参数调用接口. assert:断言 snippets提供了一些断言的使用方法. 在新版的postman中,test中方 ...