目录
getopt 函数
头文件 #include<unistd.h>
定义函数 int getopt(int argc,char * const argv[ ],const char * optstring);
extern char *optarg;
extern int optind, opterr, optopt;
getopt() 所设置的全局变量包括:
optarg——指向当前选项参数(如果有)的指针。
optind——再次调用 getopt() 时的下一个 argv 指针的索引。
optopt——最后一个未知选项。
函数说明:
getopt()用来分析命令行参数。参数argc和argv分别代表参数个数和内容,跟main()函数的命令行参数是一样的。
参数 optstring为选项字符串, 告知 getopt()可以处理哪个选项以及哪个选项需要参数,如果选项字符串里的字母后接着冒号“:”,则表示还有相关的参数,全域变量optarg 即会指向此额外参数。
如果在处理期间遇到了不符合optstring指定的其他选项getopt()将显示一个错误消息,并将全域变量optopt设为“?”字符,如果不希望getopt()打印出错信息,则只要将全域变量opterr设为0即可。
optstring中的指定的内容的意义(例如getopt(argc, argv, "ab:c:de::");)
1.单个字符,表示选项(如下例中的abcde各为一个选项)。
2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg(如下例中的b:c:)。
3 单个字符后跟两个冒号,表示该选项后可以跟一个参数,也可以不跟。如果跟一个参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(如上例中的e::,如果没有跟参数,则optarg = NULL)
测试代码
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ch;
while((ch = getopt(argc,argv,"a:bc::"))!= -1)
{
switch(ch)
{
case 'a':
printf("ch a:%c\n", ch);
printf("optarg a:%s\n", optarg);
printf("optind a:%d\n", optind);
printf("opterr a:%d\n", opterr);
printf("optopt a:%d\n", optopt);
printf("\n");
break;
case 'b':
printf("ch b:%c\n", ch);
printf("optarg b:%s\n", optarg);
printf("optind b:%d\n", optind);
printf("opterr b:%d\n", opterr);
printf("optopt b:%d\n", optopt);
printf("\n");
break;
case 'c':
printf("ch c:%c\n", ch);
printf("optarg c:%s\n", optarg);
printf("optind c:%d\n", optind);
printf("opterr c:%d\n", opterr);
printf("optopt c:%d\n", optopt);
printf("\n");
break;
default:
printf("ch default:%c\n", ch);
printf("optarg default:%s\n", optarg);
printf("optind default:%d\n", optind);
printf("opterr default:%d\n", opterr);
printf("optopt default:%d\n", optopt);
printf("\n");
}
}
return 0;
}
运行:
a的参数未输入,报错:option requires an argument – ‘a’,函数返回?,函数参数是null,optind—再次调用 getopt() 时的下一个 argv 指针的索引是2,opterr是1,打印错误信息,若设置opterr为0 ,则不打印错误信息,最后一个未知选项optopt是a。
正确输入a的参数,函数返回a,函数参数是hello,optind—再次调用 getopt() 时的下一个 argv 指针的索引是3,最后一个未知选项optopt没有,是0。
b选项是没有参数的,输入参数也会被忽略掉。
c选项的参数可以有,也可以没有,如果跟一个参数,参数必须紧跟在选项后不能以空格隔开。
并没有选项d,输入d后,报错:invalid option – ‘d’,函数返回?,最后一个未知的选项是d.
getopt_long函数
函数定义:int getopt_long(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);
头文件:
#include <getopt.h>
getopt被用来解析命令行选项参数。
getopt_long支持长选项的命令行解析,使用man getopt_long,得到其声明如下:
int getopt_long(int argc, char * const argv[],const char *optstring, const struct option *longopts,int *flag);
函数中的argc和argv通常直接从main()的两个参数传递而来。optsting是选项参数组成的字符串:
字符串optstring可以下列元素:
1.单个字符,表示选项,
2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
3 单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格
隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。
optstring是一个字符串,表示可以接受的参数。例如,"a:b:c:d:"
,表示可以接受的参数是a,b,c,d,其中,a和b参数后面跟有更多的参数值。(例如:-a host -b name)
参数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联合决定返回值
}
参数flag,表示当前长参数在longopts中的索引值。
给个例子:
struct option long_options[] = {
{“a123”, required_argument, 0, ‘a’},
{“c123”, no_argument, 0, ‘c’},
}
现在,如果命令行的参数是-a 123,那么调用getopt_long()将返回字符’a’,并且将字符串123由optarg返回(注意注意!字符串123由optarg带回!optarg不需要定义,在getopt.h中已经有定义),那么,如果命令行参数是-c,那么调用getopt_long()将返回字符’c’,而此时,optarg是null。最后,当getopt_long()将命令行所有参数全部解析完成后,返回-1。
required_argument(或者是1)时,参数输入格式为:–参数 值 或者 --参数=值。
optional_argument(或者是2)时,参数输入格式只能为:–参数=值。
代码示例
引用alsa库aplay.c文件中的函数参数解析代码。
static const char short_options[] = "hnlLD:qt:c:f:r:d:s:MNF:A:R:T:B:vV:IPCi"
#ifdef CONFIG_SUPPORT_CHMAP
"m:"
#endif
;
static const struct option long_options[] = {
{"help", 0, 0, 'h'},
{"version", 0, 0, OPT_VERSION},
{"list-devnames", 0, 0, 'n'},
{"list-devices", 0, 0, 'l'},
{"list-pcms", 0, 0, 'L'},
{"device", 1, 0, 'D'},
{"quiet", 0, 0, 'q'},
{"file-type", 1, 0, 't'},
{"channels", 1, 0, 'c'},
{"format", 1, 0, 'f'},
{"rate", 1, 0, 'r'},
{"duration", 1, 0 ,'d'},
{"samples", 1, 0, 's'},
{"mmap", 0, 0, 'M'},
{"nonblock", 0, 0, 'N'},
{"period-time", 1, 0, 'F'},
{"period-size", 1, 0, OPT_PERIOD_SIZE},
{"avail-min", 1, 0, 'A'},
{"start-delay", 1, 0, 'R'},
{"stop-delay", 1, 0, 'T'},
{"buffer-time", 1, 0, 'B'},
{"buffer-size", 1, 0, OPT_BUFFER_SIZE},
{"verbose", 0, 0, 'v'},
{"vumeter", 1, 0, 'V'},
{"separate-channels", 0, 0, 'I'},
{"playback", 0, 0, 'P'},
{"capture", 0, 0, 'C'},
{"disable-resample", 0, 0, OPT_DISABLE_RESAMPLE},
{"disable-channels", 0, 0, OPT_DISABLE_CHANNELS},
{"disable-format", 0, 0, OPT_DISABLE_FORMAT},
{"disable-softvol", 0, 0, OPT_DISABLE_SOFTVOL},
{"test-position", 0, 0, OPT_TEST_POSITION},
{"test-coef", 1, 0, OPT_TEST_COEF},
{"test-nowait", 0, 0, OPT_TEST_NOWAIT},
{"max-file-time", 1, 0, OPT_MAX_FILE_TIME},
{"process-id-file", 1, 0, OPT_PROCESS_ID_FILE},
{"use-strftime", 0, 0, OPT_USE_STRFTIME},
{"interactive", 0, 0, 'i'},
{"dump-hw-params", 0, 0, OPT_DUMP_HWPARAMS},
{"fatal-errors", 0, 0, OPT_FATAL_ERRORS},
#ifdef CONFIG_SUPPORT_CHMAP
{"chmap", 1, 0, 'm'},
#endif
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
switch (c) {
case 'h':
usage(command);
return 0;
case OPT_VERSION:
version();
return 0;
case 'l':
do_device_list = 1;
break;
case 'L':
do_pcm_list = 1;
break;
case 'D':
pcm_name = optarg;
break;
case 'q':
quiet_mode = 1;
break;
case 't':
if (strcasecmp(optarg, "raw") == 0)
file_type = FORMAT_RAW;
else if (strcasecmp(optarg, "voc") == 0)
file_type = FORMAT_VOC;
else if (strcasecmp(optarg, "wav") == 0)
file_type = FORMAT_WAVE;
else if (strcasecmp(optarg, "au") == 0 || strcasecmp(optarg, "sparc") == 0)
file_type = FORMAT_AU;
else {
error(_("unrecognized file format %s"), optarg);
return 1;
}
break;
case 'c':
rhwparams.channels = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid channels argument '%s'"), optarg);
return 1;
}
if (rhwparams.channels < 1 || rhwparams.channels > 256) {
error(_("value %i for channels is invalid"), rhwparams.channels);
return 1;
}
break;
case 'f':
if (strcasecmp(optarg, "cd") == 0 || strcasecmp(optarg, "cdr") == 0) {
if (strcasecmp(optarg, "cdr") == 0)
rhwparams.format = SND_PCM_FORMAT_S16_BE;
else
rhwparams.format = file_type == FORMAT_AU ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE;
rhwparams.rate = 44100;
rhwparams.channels = 2;
} else if (strcasecmp(optarg, "dat") == 0) {
rhwparams.format = file_type == FORMAT_AU ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE;
rhwparams.rate = 48000;
rhwparams.channels = 2;
} else {
rhwparams.format = snd_pcm_format_value(optarg);
if (rhwparams.format == SND_PCM_FORMAT_UNKNOWN) {
error(_("wrong extended format '%s'"), optarg);
prg_exit(EXIT_FAILURE);
}
}
break;
case 'r':
tmp = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid rate argument '%s'"), optarg);
return 1;
}
if (tmp < 1000)
tmp *= 1000;
rhwparams.rate = tmp;
if (tmp < 2000 || tmp > 768000) {
error(_("bad speed value %i"), tmp);
return 1;
}
break;
case 'd':
if (duration_or_sample) {
error(_("duration and samples arguments cannot be used together"));
return 1;
}
timelimit = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid duration argument '%s'"), optarg);
return 1;
}
duration_or_sample = 1;
break;
case 's':
if (duration_or_sample) {
error(_("samples and duration arguments cannot be used together"));
return 1;
}
sampleslimit = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid samples argument '%s'"), optarg);
return 1;
}
duration_or_sample = 1;
break;
case 'N':
nonblock = 1;
open_mode |= SND_PCM_NONBLOCK;
break;
case 'F':
period_time = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid period time argument '%s'"), optarg);
return 1;
}
break;
case 'B':
buffer_time = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid buffer time argument '%s'"), optarg);
return 1;
}
break;
case OPT_PERIOD_SIZE:
period_frames = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid period size argument '%s'"), optarg);
return 1;
}
break;
case OPT_BUFFER_SIZE:
buffer_frames = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid buffer size argument '%s'"), optarg);
return 1;
}
break;
case 'A':
avail_min = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid min available space argument '%s'"), optarg);
return 1;
}
break;
case 'R':
start_delay = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid start delay argument '%s'"), optarg);
return 1;
}
break;
case 'T':
stop_delay = parse_long(optarg, &err);
if (err < 0) {
error(_("invalid stop delay argument '%s'"), optarg);
return 1;
}
break;
case 'v':
verbose++;
if (verbose > 1 && !vumeter)
vumeter = VUMETER_MONO;
break;
case 'V':
if (*optarg == 's')
vumeter = VUMETER_STEREO;
else if (*optarg == 'm')
vumeter = VUMETER_MONO;
else
vumeter = VUMETER_NONE;
break;
case 'M':
mmap_flag = 1;
break;
case 'I':
interleaved = 0;
break;
case 'P':
stream = SND_PCM_STREAM_PLAYBACK;
command = "aplay";
break;
case 'C':
stream = SND_PCM_STREAM_CAPTURE;
command = "arecord";
start_delay = 1;
if (file_type == FORMAT_DEFAULT)
file_type = FORMAT_WAVE;
break;
case 'i':
interactive = 1;
break;
case OPT_DISABLE_RESAMPLE:
open_mode |= SND_PCM_NO_AUTO_RESAMPLE;//禁用自动重采样
break;
case OPT_DISABLE_CHANNELS:
open_mode |= SND_PCM_NO_AUTO_CHANNELS;//禁用自动通道转换
break;
case OPT_DISABLE_FORMAT:
open_mode |= SND_PCM_NO_AUTO_FORMAT;//禁用自动格式转换
break;
case OPT_DISABLE_SOFTVOL:
open_mode |= SND_PCM_NO_SOFTVOL;//禁用软件卷控制(Softvol)
break;
case OPT_TEST_POSITION://测试环缓冲位置
test_position = 1;
break;
case OPT_TEST_COEF:
test_coef = parse_long(optarg, &err);//用于验证的环缓冲区位置的测试系数(默认为8)表达式为:coef*(Buffer_size/2)
if (err < 0) {
error(_("invalid test coef argument '%s'"), optarg);
return 1;
}
if (test_coef < 1)
test_coef = 1;
break;
case OPT_TEST_NOWAIT:
test_nowait = 1;//不要等待环形缓冲区-这个吃掉整个cpu。
break;
case OPT_MAX_FILE_TIME:
max_file_time = parse_long(optarg, &err);//当旧文件记录了这么多秒后,启动另一个输出文件
if (err < 0) {
error(_("invalid max file time argument '%s'"), optarg);
return 1;
}
break;
case OPT_PROCESS_ID_FILE:
pidfile_name = optarg;//在这里写进程id
break;
case OPT_USE_STRFTIME:
use_strftime = 1; //将strftime工具应用于输出文件名。
break;
case OPT_DUMP_HWPARAMS:
dump_hw_params = 1; //转储设备的HW参数
break;
case OPT_FATAL_ERRORS:
fatal_errors = 1;//将所有错误视为致命错误
break;
#ifdef CONFIG_SUPPORT_CHMAP
case 'm':
channel_map = snd_pcm_chmap_parse_string(optarg);//给出要覆盖或遵循的通道映射
if (!channel_map) {
fprintf(stderr, _("Unable to parse channel map string: %s\n"), optarg);
return 1;
}
break;
#endif
default:
fprintf(stderr, _("Try `%s --help' for more information.\n"), command);
return 1;
}
}