一、简介

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. ubuntu16.04 tensorflow pip 方式安装

    首先,需要知道   tensorflow  1.5版本以上包括 1.5版本  的GPU类型都是需要安装  cuda9.0的,  tensorflow-gpu  1.4版本是可以使用cuda 8.0. ...

  2. 《Java技术》预备作业总结

    Java预备作业总结 第一次的博客作业完成了,对于一种崭新的形式,大家可能还不太适应,学习和借鉴好的理念和学习方式,是我们缩小差距.提升自己的第一步. 关于你期望的师生关系 从幼儿园到大学,大家接触到 ...

  3. LightOJ - 1205:Palindromic Numbers (数位DP&回文串)

    A palindromic number or numeral palindrome is a 'symmetrical' number like 16461 that remains the sam ...

  4. MacOS 如何截屏

    在Mac OS X下有很强大的截屏功能,它不仅仅是对屏幕的全屏COPY,而是包括很多细节在里面,就从这点来看,已经比过所有版本的Windows了. 下面我来向大家详细介绍一下: 对全屏的截图我们可以通 ...

  5. nexus 使用Raw Repositories 进行maven site 发布

    实际项目中我们可能需要进行maven 项目的site 文档发布,一般的处理是生成之后,然后在进行发布到一个静态 服务器进行页面访问,nexus3 提供了一个Raw Repositories 很方便可以 ...

  6. POJ3662电缆

    题目:http://poj.org/problem?id=3662 二分答案.然后边权>mid的边的边权2记为1,否则记为0.找一个边权2的最短路,看dis[n]是否<=K. 别忘了不能到 ...

  7. NGINX 添加MP4、FLV视频支持模块

    由于公司网站需要放置视频,但是默认的服务器环境是没有编译这个支持的模块,视频文件只能缓冲完了在播放,非常麻烦.   之前呢也安装了一个nginx_mod_h264_streaming来支持,效果很不错 ...

  8. ubuntu安装了mysql 但是编译报错 mysql.h: No such file or directory

    在Ubuntu体系中,已经安装了mysql,即应用sudo apt-get install mysql-server mysql-client 但是用C编译mysql数据库时,报错fatal erro ...

  9. ipython的使用

    改初始路径 还有一个坑,可以用notebook打开一个已经存在的文件,但是不能正常编辑(使用单元编辑),因为使用这个创建的东西根本就不是一个.py文件,如果代码编辑完毕,倒是可以通过下载那里选择下载成 ...

  10. PhpStorm 配置在浏览器中打开文件

    这东东中文资料太少- -鼓捣了好久才有结果 点击File-Settings-Deployment .点+按钮增加服务器 Mapping 设置工程路径等 点击 Edit Confi 这东东中文资料太少- ...