linux——getopt()和getopt_long()函数及optarg,optind, opterr, optopt全局变量

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014470361/article/details/84110216

getopt() 函数

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;
		}
	}

猜你喜欢

转载自blog.csdn.net/u014470361/article/details/84110216
今日推荐