【main参数】main函数的参数|命令行参数

目录

main函数的参数

C++ 命令行参数解析

实例

说明

短选项名之 getopt()

长短选项名之 getopt_long()

长短选项名之 getopt_long_only()

argagg, 一个简单的C++11 命令行 参数分析器

简介

心理模型

API参考

快速参考

结构

异常

安装

边缘案例

贪婪参数

添加参数转换

Linux下getopt()函数的简单使用



main函数的参数

第一个带参数的main。

#include <iostream.h>

 
int main(int argc,char *argv[])
{
       for(inti=0;i<argc;i++)
       {
              cout<<argv[i]<<'\t';              //
       }
       return0;
}

/*

int argc, char **argv 用于运行时,把命令行参数传入主程序。

argc -- 命令行参数总个数,包括 可执行程序名。

argv[i] -- 第 i 个参数。

argv[0] -- 可执行程序名。

*/

关于带参数的main函数网络收集:
int main(int argc,char **argv) 这里面的**argv含义··

是用来传递参数的,假如你编译成的文件名是a.exe,那么在命令提示符下可以通过a.exe12 34来向程序传递参数,这时两个参数就会传递到字符串数组argv中,注意此时实际传递了三个参数,第一个参数是文件名,第二个参数是12,第三个是34,而argc就是参数个数。

int argc, char **argv 用于运行时,把命令行参数传入主程序。

argc -- 命令行参数 总个数,包括 可执行程序名。

argv[i] --  第 i 个参数。

argv[0] -- 可执行程序名。

 
// 例如运行:

abc.exe

argc 等于 1, argv[0] 是 "abc.exe"

// 例如运行:

rec.exe  4  5.2

argc 等于 3, argv[0] 是 "rec.exe", argv[1] 是 "4", argv[2] 是 "5.2".

主函数里若有:

int x;

float y;

char s[80];

strcpy(s,argv[0]);  // 程序名存入 了 s

sscanf(argv[1],"%d",&x);  // x 得到数值4

sscanf(argv[2],"%f",&y);  // y 得到数值 5.2


ANSI-C(C89/C99)的话main()函数有2种主要形式。 

(1) int main(void) 
(2) int main(int argc, char *argv[]) 

(2)也可写成int main(int argc, char **argv) 
argv[argc]放空指针(NULL指针)。 
argc和argv可以用别名。 

另外,还有一种受系统限制的形式: 
int main(int argc, char *argv[], char *envp[]) 
前两个参数同(2),第三个参数envp[]放环境变量。 
这个形式很少用。 

所以严格讲, 
ANSI-C推荐的带参数的main()函数只有上面(2)这一种。 

另外,搜集了一下C和C++中常见的几种形式: 

(1) main() 
(2) int main() 
(3) int main(void) 
(4) int main(int, char**) 
(5) int main(int, char*[]) 
(6) int main(int argc, char **argv) 
(7) int main(int argc, char *argv[]) 
(8) int main( int argc, char *argv[], char*envp[]) 
(9) void main(void) 

(1)是(3)的简写。不推荐使用。 
(2)是(3)的简写。在C++中是正确的形式。 
(3)在C和C++中都是正确的形式。推荐使用。(还有缺省int的main(void)形式)。 
(4)和(5)是不用参数时的一种写法。编译器级别高时会警告。不推荐使用。 
(6)是(7)的另外写法。两种都可以,凭个人爱好。 
(7)是带参数的正确的形式。推荐使用。 
(8)是一种很少用的写法,且受系统限制。 
(9)一般不认为是正确的写法。但是在嵌入式系统中有使用(包括void main()形式)

原文:http://www.cnblogs.com/zerocc/archive/2010/12/17/1909642.html

C++ 命令行参数解析

实例

RDMA 测试工具  ib_write_bw 效果

源码地址:GitHub - linux-rdma/perftest: Infiniband Verbs Performance Tests

[root@rdma64 ibdump-master]# ib_write_bw -h
Usage:
  ib_write_bw            start a server and wait for connection
  ib_write_bw <host>     connect to server at <host>

Options:
  -a, --all  Run sizes from 2 till 2^23
  -b, --bidirectional  Measure bidirectional bandwidth (default unidirectional)
  -c, --connection=<RC/XRC/UC/DC>  Connection type RC/XRC/UC/DC (default RC)
  -d, --ib-dev=<dev>  Use IB device <dev> (default first device found)
  -D, --duration  Run test for a customized period of seconds.
  -f, --margin  measure results within margins. (default=2sec)
  -F, --CPU-freq  Do not show a warning even if cpufreq_ondemand module is loaded, and cpu-freq is not on max.
  -h, --help  Show this help screen.
  -i, --ib-port=<port>  Use port <port> of IB device (default 1)
  -I, --inline_size=<size>  Max size of message to be sent in inline
  -l, --post_list=<list size> Post list of WQEs of <list size> size (instead of single post)
  -L, --hop_limit=<hop_limit>  Set hop limit value (ttl for IPv4 RawEth QP). Values 0-255 (default 64)
  -m, --mtu=<mtu>  MTU size : 256 - 4096 (default port mtu)
  -n, --iters=<iters>  Number of exchanges (at least 5, default 5000)
  -N, --noPeak Cancel peak-bw calculation (default with peak up to iters=20000)
  -O, --dualport  Run test in dual-port mode.
  -p, --port=<port>  Listen on/connect to port <port> (default 18515)
  -q, --qp=<num of qp's>  Num of qp's(default 1)
  -Q, --cq-mod  Generate Cqe only after <--cq-mod> completion
  -R, --rdma_cm  Connect QPs with rdma_cm and run test on those QPs
  -s, --size=<size>  Size of message to exchange (default 65536)
  -S, --sl=<sl>  SL (default 0)
  -t, --tx-depth=<dep>  Size of tx queue (default 128)
  -T, --tos=<tos value>  Set <tos_value> to RDMA-CM QPs. available only with -R flag. values 0-256 (default off)
  -u, --qp-timeout=<timeout>  QP timeout, timeout value is 4 usec * 2 ^(timeout), default 14
  -V, --version  Display version number
  -w, --limit_bw=<value>  Set verifier limit for bandwidth
  -x, --gid-index=<index>  Test uses GID with GID index (Default : IB - no gid . ETH - 0)
  -y, --limit_msgrate=<value>  Set verifier limit for Msg Rate
  -z, --com_rdma_cm  Communicate with rdma_cm module to exchange data - use regular QPs

      --cpu_util  Show CPU Utilization in report, valid only in Duration mode 
      --dlid  Set a Destination LID instead of getting it from the other side.
      --dont_xchg_versions  Do not exchange versions and MTU with other side 
      --force-link=<value>  Force the link(s) to a specific type: IB or Ethernet.
      --ipv6  Use IPv6 GID. Default is IPv4
      --mmap=file  Use an mmap'd file as the buffer for testing P2P transfers.
      --mmap-offset=<offset>  Use an mmap'd file as the buffer for testing P2P transfers.
      --mr_per_qp  Create memory region for each qp.
      --odp  Use On Demand Paging instead of Memory Registration.
      --output=<units> Set verbosity output level: bandwidth , message_rate, latency 
 Latency measurement is Average calculation 
      --perform_warm_up Perform some iterations before start measuring in order to warming-up memory cache, valid in Atomic, Read and Write BW tests
      --pkey_index=<pkey index> PKey index to use for QP
      --report-both  Report RX & TX results separately on Bidirectinal BW tests
      --report_gbits  Report Max/Average BW of test in Gbit/sec (instead of MB/sec)
        Note: MB=2^20 byte, while Gb=10^9 bits. Use these formulas for conversion:
        Factor=10^9/(20^2*8)=119.2; MB=Gb_result * factor; Gb=MB_result / factor
      --report-per-port  Report BW data on both ports when running Dualport and Duration mode
      --reversed  Reverse traffic direction - Server send to client
      --run_infinitely  Run test forever, print results every <duration> seconds
      --retry_count=<value>  Set retry count value in rdma_cm mode
      --tclass=<value>  Set the Traffic Class in GRH (if GRH is in use)
      --use_exp  Use Experimental verbs in data path. Default is OFF.
      --use_hugepages  Use Hugepages instead of contig, memalign allocations.
      --use_res_domain  Use shared resource domain
      --verb_type=<option>  Set verb type: normal, accl. Default is normal.
      --wait_destroy=<seconds>  Wait <seconds> before destroying allocated resources (QP/CQ/PD/MR..)

 Rate Limiter:
      --burst_size=<size> Set the amount of messages to send in a burst when using rate limiter
      --typical_pkt_size=<bytes> Set the size of packet to send in a burst. Only supports PP rate limiter
      --rate_limit=<rate> Set the maximum rate of sent packages. default unit is [Gbps]. use --rate_units to change that.
      --rate_units=<units> [Mgp] Set the units for rate limit to MBps (M), Gbps (g) or pps (p). default is Gbps (g).
        Note (1): pps not supported with HW limit.
        Note (2): When using PP rate_units is forced to Kbps.
      --rate_limit_type=<type> [HW/SW/PP] Limit the QP's by HW, PP or by SW. Disabled by default. When rate_limit is not specified HW limit is Default.
        Note: in Latency under load test SW rate limit is forced
      --use_ooo  Use out of order data placement

代码

int main(int argc, char *argv[])
{

ret_parser = parser(&user_param,argv,argc);

}




 ******************************************************************************/
int parser(struct perftest_parameters *user_param,char *argv[], int argc)
{
	int c,size_len;
	int size_factor = 1;
	static int run_inf_flag = 0;
	static int report_fmt_flag = 0;
	static int srq_flag = 0;
	static int report_both_flag = 0;
	static int is_reversed_flag = 0;
	static int pkey_flag = 0;
	static int inline_recv_flag = 0;
	static int tcp_flag = 0;
	static int burst_size_flag = 0;
	static int typical_pkt_size_flag = 0;
	static int rate_limit_flag = 0;
	static int rate_units_flag = 0;
	static int rate_limit_type_flag = 0;
	static int verbosity_output_flag = 0;
	static int cpu_util_flag = 0;
	static int latency_gap_flag = 0;
	static int flow_label_flag = 0;
	static int retry_count_flag = 0;
	static int dont_xchg_versions_flag = 0;
#ifdef HAVE_CUDA
	static int use_cuda_flag = 0;
	static int use_cuda_bus_id_flag = 0;
#endif
#ifdef HAVE_ROCM
	static int use_rocm_flag = 0;
#endif
	static int disable_pcir_flag = 0;
	static int mmap_file_flag = 0;
	static int mmap_offset_flag = 0;
	static int ipv6_flag = 0;
	static int raw_ipv6_flag = 0;
	static int report_per_port_flag = 0;
	static int odp_flag = 0;
	static int hugepages_flag = 0;
	static int old_post_send_flag = 0;
	static int use_promiscuous_flag = 0;
	static int use_sniffer_flag = 0;
	static int raw_mcast_flag = 0;
	static int use_res_domain_flag = 0;
	static int mr_per_qp_flag = 0;
	static int dlid_flag = 0;
	static int tclass_flag = 0;
	static int wait_destroy_flag = 0;
	static int flows_flag = 0;
	static int flows_burst_flag = 0;
	static int force_link_flag = 0;
	static int local_ip_flag = 0;
	static int remote_ip_flag = 0;
	static int local_port_flag = 0;
	static int remote_port_flag = 0;
	static int local_mac_flag = 0;
	static int remote_mac_flag = 0;
	static int reply_every_flag = 0;
	static int perform_warm_up_flag = 0;
	static int use_ooo_flag = 0;
	static int vlan_en = 0;
	static int vlan_pcp_flag = 0;
	static int recv_post_list_flag = 0;

	char *server_ip = NULL;
	char *client_ip = NULL;
	char *local_ip = NULL;
	char *remote_ip = NULL;

	init_perftest_params(user_param);

	if(user_param->connection_type == RawEth)
		user_param->machine = UNCHOSEN;

	while (1) {
		static const struct option long_options[] = {
			{ .name = "port",		.has_arg = 1, .val = 'p' },
			{ .name = "ib-dev",		.has_arg = 1, .val = 'd' },
			{ .name = "ib-port",		.has_arg = 1, .val = 'i' },
			{ .name = "mtu",		.has_arg = 1, .val = 'm' },
			{ .name = "size",		.has_arg = 1, .val = 's' },
			{ .name = "iters",		.has_arg = 1, .val = 'n' },
			{ .name = "tx-depth",		.has_arg = 1, .val = 't' },
			{ .name = "qp-timeout",		.has_arg = 1, .val = 'u' },
			{ .name = "sl",			.has_arg = 1, .val = 'S' },
			{ .name = "gid-index",		.has_arg = 1, .val = 'x' },
			{ .name = "all",		.has_arg = 0, .val = 'a' },
			{ .name = "CPU-freq",		.has_arg = 0, .val = 'F' },
			{ .name = "connection",		.has_arg = 1, .val = 'c' },
			{ .name = "qp",			.has_arg = 1, .val = 'q' },
			{ .name = "events",		.has_arg = 0, .val = 'e' },
			{ .name = "vector",		.has_arg = 1, .val = 'X' },
			{ .name = "inline_size",	.has_arg = 1, .val = 'I' },
			{ .name = "outs",		.has_arg = 1, .val = 'o' },
			{ .name = "mcg",		.has_arg = 0, .val = 'g' },
			{ .name = "comm_rdma_cm",	.has_arg = 0, .val = 'z' },
			{ .name = "rdma_cm",		.has_arg = 0, .val = 'R' },
			{ .name = "tos",		.has_arg = 1, .val = 'T' },
			{ .name = "hop_limit",		.has_arg = 1, .val = 'L' },
			{ .name = "help",		.has_arg = 0, .val = 'h' },
			{ .name = "MGID",		.has_arg = 1, .val = 'M' },
			{ .name = "rx-depth",		.has_arg = 1, .val = 'r' },
			{ .name = "bidirectional",	.has_arg = 0, .val = 'b' },
			{ .name = "cq-mod",		.has_arg = 1, .val = 'Q' },
			{ .name = "noPeak",		.has_arg = 0, .val = 'N' },
			{ .name = "version",		.has_arg = 0, .val = 'V' },
			{ .name = "report-cycles",	.has_arg = 0, .val = 'C' },
			{ .name = "report-histogrm",	.has_arg = 0, .val = 'H' },
			{ .name = "report-unsorted",	.has_arg = 0, .val = 'U' },
			{ .name = "atomic_type",	.has_arg = 1, .val = 'A' },
			{ .name = "dualport",		.has_arg = 0, .val = 'O' },
			{ .name = "post_list",		.has_arg = 1, .val = 'l' },
			{ .name = "duration",		.has_arg = 1, .val = 'D' },
			{ .name = "margin",		.has_arg = 1, .val = 'f' },
			{ .name = "source_mac",		.has_arg = 1, .val = 'B' },
			{ .name = "dest_mac",		.has_arg = 1, .val = 'E' },
			{ .name = "dest_ip",		.has_arg = 1, .val = 'J' },
			{ .name = "source_ip",		.has_arg = 1, .val = 'j' },
			{ .name = "dest_port",		.has_arg = 1, .val = 'K' },
			{ .name = "source_port",	.has_arg = 1, .val = 'k' },
			{ .name = "ethertype",		.has_arg = 1, .val = 'Y' },
			{ .name = "limit_bw",		.has_arg = 1, .val = 'w' },
			{ .name = "limit_msgrate",	.has_arg = 1, .val = 'y' },
			{ .name = "server",		.has_arg = 0, .val = 'Z' },
			{ .name = "client",		.has_arg = 0, .val = 'P' },
			{ .name = "mac_fwd",		.has_arg = 0, .val = 'v' },
			{ .name = "use_rss",		.has_arg = 0, .val = 'G' },
			{ .name = "report-counters",	.has_arg = 1, .val = 'W' },
			{ .name = "force-link",		.has_arg = 1, .flag = &force_link_flag, .val = 1},
			{ .name = "remote_mac",		.has_arg = 1, .flag = &remote_mac_flag, .val = 1 },
			{ .name = "local_mac",		.has_arg = 1, .flag = &local_mac_flag, .val = 1 },
			{ .name = "remote_ip",		.has_arg = 1, .flag = &remote_ip_flag, .val = 1 },
			{ .name = "local_ip",		.has_arg = 1, .flag = &local_ip_flag, .val = 1 },
			{ .name = "remote_port",	.has_arg = 1, .flag = &remote_port_flag, .val = 1 },
			{ .name = "local_port",		.has_arg = 1, .flag = &local_port_flag, .val = 1 },
			{ .name = "run_infinitely",	.has_arg = 0, .flag = &run_inf_flag, .val = 1 },
			{ .name = "report_gbits",	.has_arg = 0, .flag = &report_fmt_flag, .val = 1},
			{ .name = "use-srq",		.has_arg = 0, .flag = &srq_flag, .val = 1},
			{ .name = "report-both",	.has_arg = 0, .flag = &report_both_flag, .val = 1},
			{ .name = "reversed",		.has_arg = 0, .flag = &is_reversed_flag, .val = 1},
			{ .name = "pkey_index",		.has_arg = 1, .flag = &pkey_flag, .val = 1},
			{ .name = "inline_recv",	.has_arg = 1, .flag = &inline_recv_flag, .val = 1},
			{ .name = "tcp",		.has_arg = 0, .flag = &tcp_flag, .val = 1},
			{ .name = "burst_size",		.has_arg = 1, .flag = &burst_size_flag, .val = 1},
			{ .name = "typical_pkt_size",	.has_arg = 1, .flag = &typical_pkt_size_flag, .val = 1},
			{ .name = "rate_limit",		.has_arg = 1, .flag = &rate_limit_flag, .val = 1},
			{ .name = "rate_limit_type",	.has_arg = 1, .flag = &rate_limit_type_flag, .val = 1},
			{ .name = "rate_units",		.has_arg = 1, .flag = &rate_units_flag, .val = 1},
			{ .name = "output",		.has_arg = 1, .flag = &verbosity_output_flag, .val = 1},
			{ .name = "cpu_util",		.has_arg = 0, .flag = &cpu_util_flag, .val = 1},
			{ .name = "latency_gap",	.has_arg = 1, .flag = &latency_gap_flag, .val = 1},
			{ .name = "flow_label",		.has_arg = 1, .flag = &flow_label_flag, .val = 1},
			{ .name = "retry_count",	.has_arg = 1, .flag = &retry_count_flag, .val = 1},
			{ .name = "dont_xchg_versions",	.has_arg = 0, .flag = &dont_xchg_versions_flag, .val = 1},
			#ifdef HAVE_CUDA
			{ .name = "use_cuda",		.has_arg = 1, .flag = &use_cuda_flag, .val = 1},
			{ .name = "use_cuda_bus_id",	.has_arg = 1, .flag = &use_cuda_bus_id_flag, .val = 1},
			#endif
			#ifdef HAVE_ROCM
			{ .name = "use_rocm",		.has_arg = 1, .flag = &use_rocm_flag, .val = 1},
			#endif
			{ .name = "mmap",		.has_arg = 1, .flag = &mmap_file_flag, .val = 1},
			{ .name = "mmap-offset",	.has_arg = 1, .flag = &mmap_offset_flag, .val = 1},
			{ .name = "ipv6",		.has_arg = 0, .flag = &ipv6_flag, .val = 1},
			#ifdef HAVE_IPV6
			{ .name = "raw_ipv6",		.has_arg = 0, .flag = &raw_ipv6_flag, .val = 1},
			#endif
			{.name = "report-per-port", .has_arg = 0, .flag = &report_per_port_flag, .val = 1},
			{.name = "odp", .has_arg = 0, .flag = &odp_flag, .val = 1},
			{.name = "use_hugepages", .has_arg = 0, .flag = &hugepages_flag, .val = 1},
			{.name = "use_old_post_send", .has_arg = 0, .flag = &old_post_send_flag, .val = 1},
			{.name = "promiscuous", .has_arg = 0, .flag = &use_promiscuous_flag, .val = 1},
			#if defined HAVE_SNIFFER
			{.name = "sniffer", .has_arg = 0, .flag = &use_sniffer_flag, .val = 1},
			#endif
			{.name = "raw_mcast", .has_arg = 0, .flag = &raw_mcast_flag, .val = 1},

			{.name = "mr_per_qp", .has_arg = 0, .flag = &mr_per_qp_flag, .val = 1},
			{.name = "dlid", .has_arg = 1, .flag = &dlid_flag, .val = 1},
			{.name = "tclass", .has_arg = 1, .flag = &tclass_flag, .val = 1},
			{.name = "wait_destroy", .has_arg = 1, .flag = &wait_destroy_flag, .val = 1},
			{.name = "flows", .has_arg = 1, .flag = &flows_flag, .val = 1},
			{.name = "flows_burst", .has_arg = 1, .flag = &flows_burst_flag, .val = 1},
			{.name = "reply_every", .has_arg = 1, .flag = &reply_every_flag, .val = 1},
			{.name = "perform_warm_up", .has_arg = 0, .flag = &perform_warm_up_flag, .val = 1},
			{.name = "vlan_en", .has_arg = 0, .flag = &vlan_en, .val = 1},
			{.name = "vlan_pcp", .has_arg = 1, .flag = &vlan_pcp_flag, .val = 1},
			{.name = "recv_post_list", .has_arg = 1, .flag = &recv_post_list_flag, .val = 1},
			#if defined HAVE_RO
			{.name = "disable_pcie_relaxed", .has_arg = 0, .flag = &disable_pcir_flag, .val = 1 },
			#endif
			#if defined HAVE_OOO_ATTR
			{.name = "use_ooo", .has_arg = 0, .flag = &use_ooo_flag, .val = 1},
			#endif
			{0}
		};
		c = getopt_long(argc,argv,"w:y:p:d:i:m:s:n:t:u:S:x:c:q:I:o:M:r:Q:A:l:D:f:B:T:L:E:J:j:K:k:X:W:aFegzRvhbNVCHUOZP",long_options,NULL);

		if (c == -1)
			break;

		switch (c) {

			case 'p': user_param->port = strtol(optarg, NULL, 0); break;
			case 'd': GET_STRING(user_param->ib_devname,strdupa(optarg)); break;
			case 'i': user_param->ib_port = strtol(optarg, NULL, 0);
				  if (user_param->ib_port < MIN_IB_PORT) {
					  fprintf(stderr, "IB Port can't be less than %d\n", MIN_IB_PORT);
					  return 1;
				  }
				  break;
			case 'm': user_param->mtu  = strtol(optarg, NULL, 0); break;
			case 'n': CHECK_VALUE(user_param->iters,int,MIN_ITER,MAX_ITER,"Iteration num"); break;
			case 't': CHECK_VALUE(user_param->tx_depth,int,MIN_TX,MAX_TX,"Tx depth"); break;
			case 'T': CHECK_VALUE(user_param->tos,int,MIN_TOS,MAX_TOS,"TOS"); break;
			case 'L': CHECK_VALUE(user_param->hop_limit,int,MIN_HOP_LIMIT,MAX_HOP_LIMIT,"Hop Limit"); break;
			case 'u': user_param->qp_timeout = (uint8_t)strtol(optarg, NULL, 0); break;
			case 'S': user_param->sl = (uint8_t)strtol(optarg, NULL, 0);
				  if (user_param->sl > MAX_SL) {
					  fprintf(stderr," Only %d Service levels\n",MAX_SL);
					  return 1;
				  }
				  if (user_param->connection_type == RawEth)
					  user_param->raw_qos = 1;
				  break;
			case 'x': CHECK_VALUE(user_param->gid_index, uint8_t, MIN_GID_IX, MAX_GID_IX, "Gid index");
				  user_param->use_gid_user = 1; break;
			case 'c': change_conn_type(&user_param->connection_type,user_param->verb,optarg); break;
			case 'q': if (user_param->tst != BW) {
					fprintf(stderr," Multiple QPs only available on bw tests\n");
					return 1;
				  }
				  CHECK_VALUE(user_param->num_of_qps,int,MIN_QP_NUM,MAX_QP_NUM,"num of Qps");
				  break;
			case 'I': CHECK_VALUE(user_param->inline_size,int,0,MAX_INLINE,"Max inline");
				  if (user_param->verb == READ || user_param->verb ==ATOMIC) {
					  fprintf(stderr," Inline feature not available on READ/Atomic verbs\n");
					  return 1;
				  } break;
			case 'o': user_param->out_reads = strtol(optarg, NULL, 0);
				  if (user_param->verb != READ && user_param->verb != ATOMIC) {
					  fprintf(stderr," Setting Outstanding reads only available on READ verb\n");
					  return 1;
				  } break;
			case 'M': GET_STRING(user_param->user_mgid,strdupa(optarg)); break;
			case 'r': CHECK_VALUE(user_param->rx_depth,int,MIN_RX,MAX_RX," Rx depth");
				  if (user_param->verb != SEND && user_param->rx_depth > DEF_RX_RDMA) {
					  fprintf(stderr," On RDMA verbs rx depth can be only 1\n");
					  return 1;
				  } break;
			case 'Q': CHECK_VALUE(user_param->cq_mod,int,MIN_CQ_MOD,MAX_CQ_MOD,"CQ moderation");
				  user_param->req_cq_mod = 1;
				  break;
			case 'A':
				  if (user_param->verb != ATOMIC) {
					  fprintf(stderr," You are not running the atomic_lat/bw test!\n");
					  fprintf(stderr," To change the atomic action type, you must run one of the atomic tests\n");
					  return 1;
				  }

				  if (strcmp(atomicTypesStr[0],optarg)==0)
					  user_param->atomicType = CMP_AND_SWAP;

				  else if (strcmp(atomicTypesStr[1],optarg)==0)
					  user_param->atomicType = FETCH_AND_ADD;

				  else {
					  fprintf(stderr," Invalid Atomic type! please choose from {CMP_AND_SWAP,FETCH_AND_ADD}\n");
					  exit(1);
				  }
				  break;
			case 'l': user_param->post_list = strtol(optarg, NULL, 0); break;
			case 'D': user_param->duration = strtol(optarg, NULL, 0);
				  if (user_param->duration <= 0) {
					  fprintf(stderr," Duration period must be greater than 0\n");
					  return 1;
				  }
				  user_param->test_type = DURATION;
				  break;
			case 'f': user_param->margin = strtol(optarg, NULL, 0);
				  if (user_param->margin < 0) {
					  fprintf(stderr," margin must be positive.\n");
					  return 1;
				  } break;
			case 'O':
				  user_param->ib_port  = DEF_IB_PORT;
				  user_param->ib_port2 = DEF_IB_PORT2;
				  user_param->dualport = ON;
				  break;
			case 'a': user_param->test_method = RUN_ALL; break;
			case 'F': user_param->cpu_freq_f = ON; break;
			case 'V': printf("Version: %s\n",user_param->version); return VERSION_EXIT;
			case 'h': usage(argv[0], user_param->verb, user_param->tst, user_param->connection_type);
				  if(user_param->connection_type == RawEth) {
					  usage_raw_ethernet(user_param->tst);
				  }
				  return HELP_EXIT;
			case 'z': user_param->use_rdma_cm = ON; break;
			case 'R': user_param->work_rdma_cm = ON; break;
			case 's': size_len = (int)strlen(optarg);
				  if (optarg[size_len-1] == 'K') {
					  optarg[size_len-1] = '\0';
					  size_factor = 1024;
				  }
				  if (optarg[size_len-1] == 'M') {
					  optarg[size_len-1] = '\0';
					  size_factor = 1024*1024;
				  }
				  user_param->size = (uint64_t)strtol(optarg, NULL, 0) * size_factor;
				  user_param->req_size = 1;
				  if (user_param->size < 1 || user_param->size > (UINT_MAX / 2)) {
					  fprintf(stderr," Message Size should be between %d and %d\n",1,UINT_MAX/2);
					  return 1;
				  }
				  break;
			case 'e': user_param->use_event = ON;
				  if (user_param->verb == WRITE) {
					  fprintf(stderr," Events feature not available on WRITE verb\n");
					  return 1;
				  }
				  break;
			case 'X':
				  if (user_param->verb == WRITE) {
					  fprintf(stderr, " Events feature not available on WRITE verb\n");
					  return 1;
				  }
				  user_param->use_eq_num = ON;
				  CHECK_VALUE(user_param->eq_num, int, MIN_EQ_NUM, MAX_EQ_NUM, "EQN");
				  break;
			case 'b': user_param->duplex = ON;
				  if (user_param->tst == LAT) {
					  fprintf(stderr," Bidirectional is only available in BW test\n");
					  return 1;
				  } break;
			case 'N': user_param->noPeak = ON;
				  if (user_param->tst == LAT) {
					  fprintf(stderr," NoPeak only valid for BW tests\n");
					  return 1;
				  } break;
			case 'C':
				  if (user_param->tst != LAT) {
					  fprintf(stderr," Available only on Latency tests\n");
					  return 1;
				  }
				  user_param->r_flag->cycles = ON;
				  break;
			case 'g': user_param->use_mcg = ON;
				  if (user_param->verb != SEND) {
					  fprintf(stderr," MultiCast feature only available on SEND verb\n");
					  return 1;
				  } break;
			case 'H':
				  if (user_param->tst == BW) {
					  fprintf(stderr," Available only on Latency tests\n");
					  return 1;
				  }
				  user_param->r_flag->histogram = ON;
				  break;
			case 'U':
				  if (user_param->tst == BW) {
					fprintf(stderr," is Available only on Latency tests\n");
					  return 1;
				  }
				  user_param->r_flag->unsorted = ON;
				  break;
			case 'B':
				  user_param->is_old_raw_eth_param = 1;
				  user_param->is_source_mac = ON;
				  if(parse_mac_from_str(optarg, user_param->source_mac))
					  return FAILURE;
				  break;
			case 'E':
				  user_param->is_old_raw_eth_param = 1;
				  user_param->is_dest_mac = ON;
				  if(parse_mac_from_str(optarg, user_param->dest_mac))
					  return FAILURE;
				  break;
			case 'J':
				  user_param->is_old_raw_eth_param = 1;
				  user_param->is_server_ip = ON;
				  server_ip = optarg;
				  break;
			case 'j':
				  user_param->is_old_raw_eth_param = 1;
				  user_param->is_client_ip = ON;
				  client_ip = optarg;
				  break;
			case 'K':
				  user_param->is_old_raw_eth_param = 1;
				  user_param->is_server_port = ON;
				  user_param->server_port = strtol(optarg, NULL, 0);
				  if(OFF == check_if_valid_udp_port(user_param->server_port)) {
					  fprintf(stderr," Invalid server UDP port\n");
					  return FAILURE;
				  }
				  break;
			case 'k':
				  user_param->is_old_raw_eth_param = 1;
				  user_param->is_client_port = ON;
				  user_param->client_port = strtol(optarg, NULL, 0);
				  if(OFF == check_if_valid_udp_port(user_param->client_port)) {
					  fprintf(stderr," Invalid client UDP port\n");
					  return FAILURE;
				  }
				  break;
			case 'Y':
				  user_param->is_ethertype = ON;
				  if (parse_ethertype_from_str(optarg, &user_param->ethertype)) {
					  fprintf(stderr, " Invalid ethertype value\n");
					  return FAILURE;
				  }
				  break;
			case 'w':
				  user_param->is_limit_bw = ON;
				  user_param->limit_bw = strtof(optarg,NULL);
				  if (user_param->limit_bw < 0) {
					  fprintf(stderr, " Invalid Minimum BW Limit\n");
					  return FAILURE;
				  }
				  break;
			case 'y':
				  user_param->is_limit_msgrate = ON;
				  user_param->limit_msgrate = strtof(optarg,NULL);
				  if (user_param->limit_msgrate < 0) {
					  fprintf(stderr, " Invalid Minimum msgRate Limit\n");
					  return FAILURE;
				  }
				  break;
			case 'W':
				  if (counters_alloc(optarg, &user_param->counter_ctx)) {
					  fprintf(stderr, "Failed to parse the performance counter list\n");
					  return FAILURE;
				  }
				  break;
			case 'P': user_param->machine = CLIENT; break;
			case 'Z': user_param->machine = SERVER; break;
			case 'v': user_param->mac_fwd = ON; break;
			case 'G': user_param->use_rss = ON; break;
			case 0: /* required for long options to work. */
				if (pkey_flag) {
					user_param->pkey_index = strtol(optarg,NULL,0);
					pkey_flag = 0;
				}
				if (inline_recv_flag) {
					user_param->inline_recv_size = strtol(optarg,NULL,0);
					inline_recv_flag = 0;
				}
				if (rate_limit_flag) {
					GET_STRING(user_param->rate_limit_str ,strdupa(optarg));
					user_param->rate_limit = atof(optarg);
					if (user_param->rate_limit <= 0) {
						fprintf(stderr, " Rate limit must be non-negative\n");
						return FAILURE;
					}
					/* if not specified, choose HW rate limiter as default */
					if (user_param->rate_limit_type == DISABLE_RATE_LIMIT)
						user_param->rate_limit_type = HW_RATE_LIMIT;

					rate_limit_flag = 0;
				}
				if (burst_size_flag) {
					user_param->burst_size = strtol(optarg,NULL,0);
					if (user_param->burst_size < 0) {
						fprintf(stderr, " Burst size must be non-negative\n");
						return FAILURE;
					}
					burst_size_flag = 0;
				}
				if (typical_pkt_size_flag) {
					user_param->typical_pkt_size = strtol(optarg,NULL,0);
					if ((user_param->typical_pkt_size < 0) ||
					    (user_param->typical_pkt_size > 0xFFFF)) {
						fprintf(stderr, " Typical pkt size must be non-negative and less than 0xffff\n");
						return FAILURE;
					}
					typical_pkt_size_flag = 0;
				}
				if (rate_units_flag) {
					if (strcmp("M",optarg) == 0) {
						user_param->rate_units = MEGA_BYTE_PS;
					} else if (strcmp("g",optarg) == 0) {
						user_param->rate_units = GIGA_BIT_PS;
					} else if (strcmp("p",optarg) == 0) {
						user_param->rate_units = PACKET_PS;
					} else {
						fprintf(stderr, " Invalid rate limit units. Please use M,g or p\n");
						return FAILURE;
					}
					rate_units_flag = 0;
				}
				if (rate_limit_type_flag) {
					user_param->is_rate_limit_type = 1;
					if(strcmp("SW",optarg) == 0)
						user_param->rate_limit_type = SW_RATE_LIMIT;
					else if(strcmp("HW",optarg) == 0)
						user_param->rate_limit_type = HW_RATE_LIMIT;
					else if(strcmp("PP",optarg) == 0)
						user_param->rate_limit_type = PP_RATE_LIMIT;
					else {
						fprintf(stderr, " Invalid rate limit type flag. Please use HW, SW or PP.\n");
						return FAILURE;
					}
					rate_limit_type_flag = 0;
				}
				if (verbosity_output_flag) {
					if (strcmp("bandwidth",optarg) == 0) {
						user_param->output = OUTPUT_BW;
					} else if (strcmp("message_rate",optarg) == 0) {
						user_param->output = OUTPUT_MR;
					} else if (strcmp("latency",optarg) == 0) {
						user_param->output = OUTPUT_LAT;
					} else {
						fprintf(stderr, " Invalid verbosity level output flag. Please use bandwidth, latency, message_rate\n");
						return FAILURE;
					}
					verbosity_output_flag = 0;
				}
				if (latency_gap_flag) {
					user_param->latency_gap = strtol(optarg,NULL,0);
					if (user_param->latency_gap < 0) {
						fprintf(stderr, " Latency gap time must be non-negative\n");
						return FAILURE;
					}
					latency_gap_flag = 0;
				}
#ifdef HAVE_CUDA
				if (use_cuda_flag) {
					user_param->use_cuda = 1;
					user_param->cuda_device_id = strtol(optarg, NULL, 0);
					if (user_param->cuda_device_id < 0)
					{
						fprintf(stderr, "Invalid CUDA device %d\n", user_param->cuda_device_id);
						return FAILURE;
					}
					use_cuda_flag = 0;
				}
				if (use_cuda_bus_id_flag) {
					user_param->use_cuda = 1;
					user_param->cuda_device_bus_id = strdup(optarg);
					printf("Got PCIe address of: %s\n", user_param->cuda_device_bus_id);
					use_cuda_bus_id_flag = 0;
				}
#endif
#ifdef HAVE_ROCM
				if (use_rocm_flag) {
					user_param->use_rocm = 1;
					user_param->rocm_device_id = strtol(optarg, NULL, 0);
					if (user_param->rocm_device_id < 0)
					{
						fprintf(stderr, "Invalid ROCm device %d\n", user_param->rocm_device_id);
						return FAILURE;
					}
					use_rocm_flag = 0;
				}
#endif
				if (flow_label_flag) {
					user_param->flow_label = strtol(optarg,NULL,0);
					if (user_param->flow_label < 0) {
						fprintf(stderr, "flow label must be non-negative\n");
						return FAILURE;
					}
					flow_label_flag = 0;
				}
				if (retry_count_flag) {
					user_param->retry_count = strtol(optarg,NULL,0);
					if (user_param->retry_count < 0) {
						fprintf(stderr, " Retry Count value must be positive\n");
						return FAILURE;
					}
					retry_count_flag = 0;
				}
				if (mmap_file_flag) {
					user_param->mmap_file = strdup(optarg);
					mmap_file_flag = 0;
				}
				if (mmap_offset_flag) {
					user_param->mmap_offset = strtol(optarg, NULL, 0);
					mmap_offset_flag = 0;
				}
				if (dlid_flag) {
					user_param->dlid = (uint16_t)strtol(optarg, NULL, 0);
					dlid_flag = 0;
				}
				if (tclass_flag) {
					user_param->traffic_class = (uint16_t)strtol(optarg, NULL, 0);
					tclass_flag = 0;
				}
				if (wait_destroy_flag) {
					user_param->wait_destroy = (uint32_t)strtol(optarg, NULL, 0);
					wait_destroy_flag = 0;
				}
				if (flows_flag) {
					user_param->flows = (uint16_t)strtol(optarg, NULL, 0);
					if (user_param->flows == 0) {
						fprintf(stderr, "Invalid flows value. Please set a positive number\n");
						return FAILURE;
					}
					flows_flag = 0;
				}
				if (flows_burst_flag) {
					user_param->flows_burst = (uint16_t)strtol(optarg, NULL, 0);
					if (user_param->flows_burst == 0) {
						fprintf(stderr, "Invalid burst flow value. Please set a positive number\n");
						return FAILURE;
					}
					flows_burst_flag = 0;

				}
				if (force_link_flag) {
					user_param->link_type = str_link_layer(optarg);
					if (user_param->link_type == LINK_FAILURE) {
						fprintf(stderr, "Invalid link layer value should be IB or ETHERNET.\n");
						return FAILURE;
					}
					force_link_flag = 0;
				}
				if (remote_mac_flag) {
					user_param->is_new_raw_eth_param = 1;
					user_param->is_dest_mac = 1;
					if(parse_mac_from_str(optarg, user_param->remote_mac))
						return FAILURE;
					remote_mac_flag = 0;
				}
				if (local_mac_flag) {
					user_param->is_new_raw_eth_param = 1;
					user_param->is_source_mac = 1;
					if(parse_mac_from_str(optarg, user_param->local_mac))
						return FAILURE;
					local_mac_flag = 0;
				}
				if (remote_ip_flag) {
					user_param->is_new_raw_eth_param = 1;
					user_param->is_client_ip = 1;
					remote_ip = optarg;
					remote_ip_flag = 0;
				}
				if (local_ip_flag) {
					user_param->is_new_raw_eth_param = 1;
					user_param->is_server_ip = 1;
					local_ip = optarg;
					local_ip_flag = 0;
				}
				if (remote_port_flag) {
					user_param->is_new_raw_eth_param = 1;
					user_param->is_client_port = 1;
					user_param->remote_port = strtol(optarg, NULL, 0);
					if(OFF == check_if_valid_udp_port(user_param->remote_port)) {
						fprintf(stderr," Invalid remote UDP port\n");
						return FAILURE;
					}
					remote_port_flag = 0;
				}
				if (local_port_flag) {
					user_param->is_new_raw_eth_param = 1;
					user_param->is_server_port = 1;
					user_param->local_port = strtol(optarg, NULL, 0);
					if(OFF == check_if_valid_udp_port(user_param->local_port)) {
						fprintf(stderr," Invalid local UDP port\n");
						return FAILURE;
					}
					local_port_flag = 0;
				}
				if (reply_every_flag) {
					user_param->reply_every = strtol(optarg, NULL, 0);
					reply_every_flag = 0;
				}
				if(vlan_pcp_flag) {
					user_param->vlan_pcp = strtol(optarg, NULL, 0);
					user_param->vlan_en = ON;
					if (user_param->vlan_pcp > 8) {
						fprintf(stderr, "Invalid vlan priority value. Please set a number in 0~8\n");
						return FAILURE;
					}
					vlan_pcp_flag = 0;
				}
				if (recv_post_list_flag) {
					user_param->recv_post_list = strtol(optarg, NULL, 0);
					recv_post_list_flag = 0;
				}
				break;

			default:
				  fprintf(stderr," Invalid Command or flag.\n");
				  fprintf(stderr," Please check command line and run again.\n\n");
				  usage(argv[0], user_param->verb, user_param->tst, user_param->connection_type);
				  if(user_param->connection_type == RawEth) {
					  usage_raw_ethernet(user_param->tst);
				  }
				  return 1;
		}
	}

	if (tcp_flag) {
		user_param->tcp = 1;
	}
	if (run_inf_flag) {
		user_param->test_method = RUN_INFINITELY;
	}

	if (srq_flag) {
		user_param->use_srq = 1;
	}

	if (report_fmt_flag) {
		user_param->report_fmt = GBS;
	}

	if (dont_xchg_versions_flag) {
		user_param->dont_xchg_versions = 1;
	}

	if (use_res_domain_flag) {
		user_param->use_res_domain = 1;
	}

	if (disable_pcir_flag) {
		user_param->disable_pcir = 1;
	}

	if (report_both_flag) {
		user_param->report_both = 1;
	}

	if (is_reversed_flag) {
		user_param->is_reversed = 1;
	}

	if (cpu_util_flag) {
		user_param->cpu_util = 1;
	}

	if (report_per_port_flag) {
		user_param->report_per_port = 1;
	}

	if (ipv6_flag) {
		user_param->ipv6 = 1;
	}

	if (raw_ipv6_flag) {
		if (user_param->is_new_raw_eth_param) {
			if (user_param->is_server_ip) {
				if(1 != parse_ip6_from_str(local_ip,
							  (struct in6_addr *)&(user_param->local_ip6))) {
					fprintf(stderr," Invalid local IP address\n");
					return FAILURE;
				}
			}
			if (user_param->is_client_ip) {
				if(1 != parse_ip6_from_str(remote_ip,
							  (struct in6_addr *)&(user_param->remote_ip6))) {
					fprintf(stderr," Invalid remote IP address\n");
					return FAILURE;
				}
			}
		} else {
			if (user_param->is_server_ip) {
				if(1 != parse_ip6_from_str(server_ip,
							  (struct in6_addr *)&(user_param->server_ip6))) {
					fprintf(stderr," Invalid server IP address\n");
					return FAILURE;
				}
			}
			if (user_param->is_client_ip) {
				if(1 != parse_ip6_from_str(client_ip,
							  (struct in6_addr *)&(user_param->client_ip6))) {
					fprintf(stderr," Invalid client IP address\n");
					return FAILURE;
				}
			}
		}
		user_param->raw_ipv6 = 1;
	} else {
		if (user_param->is_new_raw_eth_param) {
			if (user_param->is_server_ip) {
				if(1 != parse_ip_from_str(local_ip,
							  &(user_param->local_ip))) {
					fprintf(stderr," Invalid local IP address\n");
					return FAILURE;
				}
			}
			if (user_param->is_client_ip) {
				if(1 != parse_ip_from_str(remote_ip,
							  &(user_param->remote_ip))) {
					fprintf(stderr," Invalid remote IP address\n");
					return FAILURE;
				}
			}
		} else {
			if (user_param->is_server_ip) {
				if(1 != parse_ip_from_str(server_ip,
							  &(user_param->server_ip))) {
					fprintf(stderr," Invalid server IP address\n");
					return FAILURE;
				}
			}
			if (user_param->is_client_ip) {
				if(1 != parse_ip_from_str(client_ip,
							  &(user_param->client_ip))) {
					fprintf(stderr," Invalid client IP address\n");
					return FAILURE;
				}
			}
		}
	}

	if(odp_flag) {
		user_param->use_odp = 1;
	}

	if(hugepages_flag) {
		user_param->use_hugepages = 1;
	}

	if(old_post_send_flag) {
		user_param->use_old_post_send = 1;
	}

	if (use_promiscuous_flag) {
		user_param->use_promiscuous = 1;
	}

	if (use_sniffer_flag) {
		user_param->use_sniffer = 1;
	}

	if (raw_mcast_flag) {
		user_param->raw_mcast = 1;
	}

	if (mr_per_qp_flag) {
		user_param->mr_per_qp = 1;
	}

	if (perform_warm_up_flag) {
		user_param->perform_warm_up = 1;
	}
	if (use_ooo_flag)
		user_param->use_ooo = 1;
	if(vlan_en) {
		user_param->vlan_en = ON;
		user_param->print_eth_func = &print_ethernet_vlan_header;
		vlan_en = 0;
	}
	if (optind == argc - 1) {
		GET_STRING(user_param->servername,strdupa(argv[optind]));

	} else if (optind < argc) {
		fprintf(stderr," Invalid Command line. Please check command rerun \n");
		return 1;
	}

	if(user_param->connection_type != RawEth)
		user_param->machine = user_param->servername ? CLIENT : SERVER;

	/* fan-in addition */
	if (user_param->is_reversed) {
		if (user_param->machine == SERVER)
			user_param->machine = CLIENT;
		else
			user_param->machine = SERVER;
	}
	set_raw_eth_parameters(user_param);
	force_dependecies(user_param);
	return 0;
}

说明


主要参考以下博客:

博客一:getopt和getopt_long函数

博客二:C++中如何自定义命令行参数——完整实例演示

博客三:使用 Qt 解析命令行参数

博客四:linux c/c++中getopt的使用

短选项名之 getopt()


头文件:#include

函数原型:int getopt(int argc, char * const argv[], const char *optstring);

参数解释:
[param1] argc: main 函数的 argc
[param2] argv: main 函数的 argv
[param3] optstring: 格式控制符。"ab:c:d"代表 -b 和 -c 选项后面有冒号,表示必须跟一个参数(如 -b 77),而 -a 和 -d 后面没有冒号,表示不需要参数,如果(gcc -g ……)详细说明见文章后面相关章节

相关变量:
extern char *optarg; 表示参数的具体内容
extern int optind; 表下一个将被处理到的参数在 argv 中的下标值
extern int opterr;
extern int optopt;

测试案例:

// Opt.cpp
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

// 短参数测试案例
void testGetOpt(int argc, char *argv[]) {
    int opt;  // getopt() 的返回值
    const char *optstring = "a:b:c:d"; // 设置短参数类型及是否需要参数

    while ((opt = getopt(argc, argv, optstring)) != -1) {
        printf("opt = %c\n", opt);  // 命令参数,亦即 -a -b -c -d
        printf("optarg = %s\n", optarg); // 参数内容
        printf("optind = %d\n", optind); // 下一个被处理的下标值
        printf("argv[optind - 1] = %s\n\n",  argv[optind - 1]); // 参数内容
    }
}

int main(int argc, char *argv[]) {
    testGetOpt(argc, argv);
    return 0;
}

正确的使用方法():

[User@ubuntu:~/Desktop]$ opt.exe -a a_para -b b_para -c c_para -d	# 参数全用
[User@ubuntu:~/Desktop]$ opt.exe -a a_para -b b_para -d				# 部分参数
[User@ubuntu:~/Desktop]$ opt.exe -b b_para -a a_para				# 可以倒序
[User@ubuntu:~/Desktop]$ opt.exe  									# 可以无参

错误的使用方法(×):

[User@ubuntu:~/Desktop]$ opt.exe -a  					# -a 后面没有跟参数
[User@ubuntu:~/Desktop]$ opt.exe -a a_para -d d_para  	# -d 后面跟了参数

长短选项名之 getopt_long()


头文件:#include

函数原型:int getopt(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

参数解释:
[param1] argc: main 函数的 argc
[param2] argv: main 函数的 argv
[param3] optstring: 格式控制符 
"ab:c:d"代表 -b 和 -c 选项后面有冒号,表示必须跟一个参数(如 -b 77),而 -a 和 -d 后面没有冒号,表示不需要参数
[param4] longopts: 一个由option结构体组成的数组,数组的每个元素,指明了一个“长参数”(即形如–name的参数)名称和性质
[param5] longindex: 如果longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值

相关变量:
同上

测试案例:

// Opt.cpp
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>

// 长参数测试案例
void testGetOptLong(int argc, char *argv[]) {
    int opt; // getopt_long() 的返回值
    int digit_optind = 0; // 设置短参数类型及是否需要参数

    // 如果option_index非空,它指向的变量将记录当前找到参数符合long_opts里的
    // 第几个元素的描述,即是long_opts的下标值
    int option_index = 0;
    // 设置短参数类型及是否需要参数
    const char *optstring = "ab:nr:";  

    // 设置长参数类型及其简写,比如 --reqarg <==>-r
    /*
    struct option {
             const char * name;  // 参数的名称
             int has_arg; // 是否带参数值,有三种:no_argument, required_argument,optional_argument
             int * flag; // 为空时,函数直接将 val 的数值从getopt_long的返回值返回出去,
                     // 当非空时,val的值会被赋到 flag 指向的整型数中,而函数返回值为0
             int val; // 用于指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值
        };
    其中:
        no_argument(即0),表明这个长参数不带参数(即不带数值,如:--name)
            required_argument(即1),表明这个长参数必须带参数(即必须带数值,如:--name Bob)
            optional_argument(即2),表明这个长参数后面带的参数是可选的,(即--name和--name Bob均可)
     */
    static struct option long_options[] = {
        {"reqarg", required_argument, NULL, 'r'},
        {"noarg",  no_argument,       NULL, 'n'},
        {"optarg", optional_argument, NULL, 'o'},
        {0, 0, 0, 0}  // 添加 {0, 0, 0, 0} 是为了防止输入空值
    };
//  {"reqarg", required_argument, NULL, 'r'},
//{.name = "reqarg", .has_arg = required_argument, .val = 'r' }
//长名 reqarg,短名 r ,required_argument 需要参数值

    while ( (opt = getopt_long(argc,
                               argv,
                               optstring,
                               long_options,
                               &option_index)) != -1) {
        printf("opt = %c\n", opt); // 命令参数,亦即 -a -b -n -r
        printf("optarg = %s\n", optarg); // 参数内容
        printf("optind = %d\n", optind); // 下一个被处理的下标值
        printf("argv[optind - 1] = %s\n",  argv[optind - 1]); // 参数内容
        printf("option_index = %d\n", option_index);  // 当前打印参数的下标值
        printf("\n");
    }
}

int main(int argc, char *argv[]) {
    testGetOptLong(argc, argv);
    return 0;
}

正确的使用方法():

[User@ubuntu:~/Desktop]$ opt.exe -a -b b_para -n -r r_para					# 全部使用
[User@ubuntu:~/Desktop]$ opt.exe -a											# 部分参数
[User@ubuntu:~/Desktop]$ opt.exe -a -b b_para								# 部分参数
[User@ubuntu:~/Desktop]$ opt.exe -a -b b_para -n							# 部分参数
[User@ubuntu:~/Desktop]$ opt.exe -n -r r_para								# 部分参数
[User@ubuntu:~/Desktop]$ opt.exe  -a --noarg --reqarg required_para			# 长参数

错误的使用方法(×):

[User@ubuntu:~/Desktop]$ opt.exe -a -b -n -r required_para		# -b 没有跟参数

注意事项:一般地,不要将短参数的 optstring 和长参数的 struct option 的 val 设置为一样的字母,这样易于区分!!!

长短选项名之 getopt_long_only()


头文件:#include

函数原型:int getopt(int argc, char * const argv[], const char *optstring, const struct option *long_opts, int *longindex);

与 getopt_long() 的区别:

  • 该函数与 getopt_long() 函数使用相同的参数表,在功能上基本一致
  • 只是 getopt_long() 只将 --name 当作长参数,但 getopt_long_only() 会将 --name 和 -name 两种选项都当作长参数来匹配
  • getopt_long() 在遇到 -name 时,会拆解成 -n -a -m -e 到 optstring 中进行匹配,而 getopt_long_only() 只在 -name 不能在longopts() 中匹配时才将其拆解成 -n -a -m -e 这样的参数到 optstring 中进行匹配

原文:C++ 命令行参数解析_Neverland_LY的博客-CSDN博客_c++ 命令行参数解析

argagg, 一个简单的C++11 命令行 参数分析器

A simple C++11 command line argument parser

  下载地址2:GitHub - liangchaoxi/comand-line-Parameter-parser: A simple C++11 command line argument parser

  • Git URL:
    git://www.github.com/vietjtnguyen/argagg.git
    Git Clone代码到本地:
    git clone http://www.github.com/vietjtnguyen/argagg
    Subversion代码到本地:
    $ svn co --depth empty http://www.github.com/vietjtnguyen/argagg
    Checked out revision 1.
    $ cd repo
    $ svn up trunk
    
    命令行参数聚合器

    这是另一个 C++ 命令行 参数/选项。 目标是以简单的方式实现大多数参数解析需求,并且使用简单的API。 它作为一个通过所有参数的操作,识别由 - ( 短) 或者 -- ( 长) 前缀的标志,并将它的集成到易于访问的结构。 它延迟了处理类型,直到访问它们,结果结构只是指向原始 命令行 参数的指针。

    argagg 支持 POSIX推荐参数语法约定插件:

    • 选项( 短) 以连字符( - ) 开始,长选项以两个连字符( -- ) 开始
    • 多个短选项可以按一个连字符进行分组
      • -a -b -c 也可以写入 -abc 或者 -bac 等。
    • 选项名称是alpha数字,但长选项可能包含连字符
      • -v 有效,--ftest-coverage 有效
      • -# 无效,--bad$option 无效
    • 短选项可以提供带有空格分隔符或者不带空格分隔符的参数
      • -I/usr/local/include 和 -I/usr/local/include 同样有效
    • 长选项可以提供带有空格或者等号分隔符的参数
      • --output test.txt 和 --output=test.txt 等价
    • 选项和位置参数可以交错
    • 可以指定 -- 以将下列所有参数视为位置参数( 例如。 非选项)

    帮助消息格式是通过 {Li,U}nix 系统上的fmt 实用程序提供的。

    项目只有一个必需的标头: argagg.hpp。 include/argagg/convert 下的可选标头包含额外的参数转换专用化。

    简介

    仅创建 argagg::parser 对象。 结构不提供任何显式方法来定义选项。 相反,我们使用初始化列表来定义选项。

    复制

    argagg::parser argparser {{
     { "help", {"-h", "--help"},
     "shows this help message", 0},
     { "delim", {"-d", "--delim"},
     "delimiter (default:, )", 1},
     { "num", {"-n", "--num"},
     "number", 1},
     }};

    选项由四个内容指定: 选项的NAME,激活选项( 标志)的字符串,选项消息的帮助以及选项期望的参数数。

    定义解析器之后,你实际上通过调用 argagg::parser::parse() 方法来解析参数。 如果存在任何问题,则引发异常。

    复制

    argagg::parser_results args;try {
     args = argparser.parse(argc, argv);
    } catch (const std::exception& e) {
     std::cerr <<e.what() <<std::endl;
     return EXIT_FAILURE;
    }

    你可以检查 命令行 参数中是否显示了选项,方法是通过从解析器结果访问 NAME 选项并使用隐式布尔转换来显示选项。 你可以通过流 argagg::parser 实例本身来写出一个简单的选项帮助消息。

    复制

    if (args["help"]) {
     std::cerr <<argparser;
     // -h, --help// shows this help message// -d, --delim// delimiter (default:, )// -n, --num// numberreturn EXIT_SUCCESS;
    }

    帮助消息仅用于标志。 如果需要使用消息,则由你提供。

    复制

    if (args["help"]) {
     std::cerr <<"Usage: program [options] ARG1 ARG2" <<std::endl
     <<argparser;
     // Usage: program [options] ARG1 ARG2// -h, --help// shows this help message// -d, --delim// delimiter (default:, )// -n, --num// numberreturn EXIT_SUCCESS;
    }

    为实现漂亮的字包装( 有关更好的示例,请参阅 ./examples/joinargs.cpp ),提供了一个特殊的输出流,它将运行使用和通过。

    复制

    if (args["help"]) {
     argagg::fmt_ostream fmt(std::cerr);
     fmt <<"Usage: program [options] ARG1 ARG2" <<std::endl
     <<argparser;
     return EXIT_SUCCESS;
    }

    通常 argagg 试图做最少的工作以将大部分控件留给用户。

    如果你想获得一个选项参数,但是如果未指定该选项,则返回默认值,然后可以使用 argagg::option_results::as() API。

    复制

    auto delim = args["delim"].as<std::string>(",");

    如果你不介意隐式转换操作符,那么允许你编写简单的赋值。

    复制

    int x = 0;if (args["num"]) {
     x = args["num"];
    }

    最后,你可以使用 argagg::parser_results::pos 成员将所有位置参数作为 std::vector 获取。 可以使用与选项参数转换方法相同的转换函数来转换单个位置参数。

    复制

    auto y = 0.0;if (args.pos.size()> 0) {
     y = args.as<double>(0);
    }

    还可以在 命令行 上指定 --,以便将所有下列参数视为非选项。

    有关更详细的处理,请看一下示例或者测试用例。

    自定义参数转换函数也可以通过 argagg::convert::arg() 或者 argagg::convert::converter 请参见 test_csv.cpp 插件,以及TEST_CASE("custom conversion function") 和 TEST_CASE("parse_next_component() example") 在 test.cpp

    心理模型

    解析器只返回原始 argv array 中指向c 字符串的指针结构。 parse() 方法返回一个包含两个内容的parser_results 对象: 位置参数和选项结果。 位置参数只是 const char*的一个 std::vector。 选项结果是从选项 NAME ( std::string ) 到 option_results 对象的映射。 option_results 对象只是 option_result 对象的std::vector。 每个 option_result 实例代表在 命令行 上显示的选项。 如果有一个参数关联,那么成员的option_resultarg 将不存在,也就是 nullptr

    请考虑以下命令:

    复制

    gcc -g -I/usr/local/include -I. -o test main.o foo.o -L/usr/local/lib -lz bar.o -lpng

    这将产生如下结构,在 psuedo: 中写入,它的中每个字符串实际上是指向原始 argv array 中某一部分的const char*

    复制

    parser_results:
     program: "gcc"pos: ["main.o","foo.o","bar.o"]options:
     version:
     debug:
     all:
     - arg: nullinclude_path:
     all:
     - arg: "/usr/local/include" - arg: "."library_path:
     all:
     - arg: "/usr/local/lib"library:
     all:
     - arg: "z" - arg: "png"output:
     all:
     - arg: "test"

    转换到类型是在使用 as() API时发生的。 到那个时候 argagg 只是在处理c 字符串。

    API参考

    可以在这里找到Doxygen文档:。

    快速参考

    结构

    • option_result
      • const char* arg
    • option_results
      • std::vector all
    • parser_results
      • const char* program
      • std::unordered_map options
      • std::vector pos
    • definition
      • const char* name
      • std::vector flag
      • std::string help
      • unsigned int num_args
    • parser_map
      • std::array short_map
      • std::unordered_map long_map
    • parser
      • std::vector definitions

    异常

    • unexpected_argument_error
    • unexpected_option_error
    • option_lacks_argument_error
    • invalid_flag

    安装

    只有一个必需的头文件( argagg.hpp ),所以你可以复制你想要的whereever。 如果你想正确安装它,你可以使用CMake脚本。 web脚本主要用于构建测试和文档,但是提供了用于安装所有头文件的头部的安装目标。

    使用CMake和 make的标准安装舞蹈如下所示:

    复制

    mkdir buildcd build
    cmake -DCMAKE_INSTALL_PREFIX=/usr/local.. 
    make install
    ctest -V # optionally run tests

    覆盖 CMAKE_INSTALL_PREFIX 更改安装位置。 默认情况下,(。在UNIX变量上) 将安装到 /usr/local 中,从而将标题复制到 /usr/local/include/argagg/argagg.hpp

    如果你拥有 ,它还应该构建和安装文档。

    除了标准库之外,没有依赖项。

    边缘案例

    有一些有趣的边缘案例出现在选项解析中。 我在这些案例中使用 gcc的行为作为目标参考。

    贪婪参数

    请记住需要参数的选项将greedily进程参数。

    假设我们有以下选项: -a-b-c 和 -o。 它们都不接受参数,除了 -o。 下面是短标志分组的排列列表和结果:

    • -abco foo-o 参数为 foo
    • -aboc foo-o 参数是 cfoo 是位置参数
    • -aobc foo-o 参数是 bcfoo 是位置参数
    • -oabc foo-o 参数是 abcfoo 是位置参数

    对于空白分隔参数,贪婪处理意味着下一个参数元素( 在 argv 中) 将被视为前一个选项的参数。 这意味着你会得到如下行为:

    • --output=foo -- --bar--output 参数是 foo--bar 是位置参数
    • --output -- --bar--output 参数为 ----bar 被视为标志
    • --output --bar--output 参数为 --bar

    添加参数转换

    通过定义函数 argagg::convert::arg<>()的模板专门化,参数被转换为类型。 整数和浮点类型的专门化在 include/argagg/argagg.hpp 中预先定义。 将参数解析为逗号分隔的字符串列表的扩展被定义为 include/argagg/convert/comma_separated_strings.hpp

原文:https://www.kutu66.com//GitHub/article_153904

Linux下getopt()函数的简单使用

Linux下getopt()函数的简单使用 - 青儿哥哥 - 博客园

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

第三个参数是个字符串,看名字,我们可以叫他选项字符串(后面会说明)

返回值为int类型,每个选项字符都有他所对应的整型值,其实这个返回值返回的就是一个字符,

简单了解了出身和原型,下面我们看看这家伙到底有什么本事吧,介绍他的几个兄弟:

小弟1、extern char* optarg; //保存选项的参数

小弟2、extern int optind;      //记录下一个检索位置

小弟3、extern int opterr;      //表示的是是否将错误信息输出到stderr,为0时表示不输出

小弟4、extern int optopt;    //表示不在选项字符串optstring中的选项

问题1:选项到底是个什么鬼?

在linux指令吧:gcc helloworld.c -o helloworld.out; 

-o就是命令行的选项,而后面的helloworld.out就是-o选项所携带的参数。

另外有些选项是不用带参数的,比如 gcc -g ……

不带参数的选项可以写在一起,比如说有两个选项-c和-d,这两个选项都不带参数可以写在一起,写成-cd的----("a:b:cd::e")实际的例子:当我们删除一个文件夹时可以使用指令 rm 目录名 -rf,本来-r表示递归删除,就是删除文件夹中所有的东西,-f表示不提示就立刻删除,他们两个都不带参数,这时他们就可以写在一起。

问题2:选项字符串又是何方神圣?

"a:b:cd::e",这就是一个选项字符串。对应到命令行就是-a ,-b ,-c ,-d, -e 。冒号表示参数,

一个冒号就表示这个选项后面必须带有参数(没有带参数会报错哦),但是这个参数可以和选项连在一起写,也可以用空格隔开,比如-a123 和-a   123(中间有空格) 都表示123是-a的参数;

两个冒号的就表示这个选项的参数是可选的,即可以有参数,也可以没有参数,但要注意有参数时,参数与选项之间不能有空格(有空格会报错的哦),这一点和一个冒号时是有区别的。

好了,先给个代码,然后再解释吧。

#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
    
    int ch;
    printf("\n\n");
    printf("optind:%d,opterr:%d\n",optind,opterr);
    printf("--------------------------\n");
       while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
       {
        printf("optind: %d\n", optind);
           switch (ch) 
        {
               case 'a':
                       printf("HAVE option: -a\n\n");   
                       break;
               case 'b':
                       printf("HAVE option: -b\n"); 
                       printf("The argument of -b is %s\n\n", optarg);
                       break;
               case 'c':
                       printf("HAVE option: -c\n");
                       printf("The argument of -c is %s\n\n", optarg);
                       break;
               case 'd':
                   printf("HAVE option: -d\n");
                     break;
              case 'e':
                    printf("HAVE option: -e\n");
                    printf("The argument of -e is %s\n\n", optarg);
                  break;
              case '?':
                       printf("Unknown option: %c\n",(char)optopt);
                       break;
               }
       }

}

编译后命令行执行:# ./main -b "qing er"

输出结果为:

optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er

我们可以看到:optind和opterr的初始值都为1,前面提到过opterr非零表示产生的错误要输出到stderr上。那么optind的初值为什么是1呢?

这就要涉及到main函数的那两个参数了,argc表示参数的个数,argv[]表示每个参数字符串,对于上面的输出argc就为3,argv[]分别为: ./main 和 -b 和"qing er" ,实际上真正的参数是用第二个-b 开始,也就是argv[1],所以optind的初始值为1;

当执行getopt()函数时,会依次扫描每一个命令行参数(从下标1开始),第一个-b,是一个选项,而且这个选项在选项字符串optstring中有,我们看到b后面有冒号,也就是b后面必须带有参数,而"qing er"就是他的参数。所以这个命令行是符合要求的。至于执行后optind为什么是3,这是因为optind是下一次进行选项搜索的开始索引,也是说下一次getopt()函数要从argv[3]开始搜索。当然,这个例子argv[3]已经没有了,此时getopt()函数就会返回-1。

再看一个输入:

 ./main -b "qing er" -c1234

输出结果为:

optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er

optind: 4
HAVE option: -c
The argument of -c is 1234

对于这个过程会调用三次getopt()函数,和第一个输入一样,是找到选项-b和他的参数"qing er",这时optind的值为3,也就意味着,下一次的getopt()要从argv[3]开始搜索,所以第二次调用getopt()函数,找到选项-c和他的参数1234(选项和参数是连在一起的),由于-c1234写在一起,所以他两占一起占用argv[3],所以下次搜索从argv[4]开始,而argv[4]为空,这样第三次调用getopt()函数就会返回-1,循环随之结束。

接下来我们看一个错误的命令行输入: ./main -z 123

输出为:

optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 2
Unknown option: z

其中./main: invalid option -- 'z'就是输出到stderr的错误输出。如果把opterr设置为0那么就不会有这条输出。

在看一个错误的命令行输入: ./main -zheng

optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 1
Unknown option: z
./main: invalid option -- 'h'
optind: 1
Unknown option: h
optind: 2
HAVE option: -e
The argument of -e is ng

前面提到过不带参数的选项可以写在一起,所以当getopt()找到-z的时候,发现在optstring 中没有,这时候他就认为h也是一个选项,也就是-h和-z写在一起了,依次类推,直到找到-e,发现optstring中有。

最后要说明一下,getopt()会改变argv[]中参数的顺序。经过多次getopt()后,argv[]中的选项和选项的参数会被放置在数组前面,而optind 会指向第一个非选项和参数的位置。看例子

#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
    
    int i;
    printf("--------------------------\n");
    for(i=0;i<argc;i++)
    {
        printf("%s\n",argv[i]);
    }
    printf("--------------------------\n");
       //int aflag=0, bflag=0, cflag=0;
    
       int ch;
    printf("\n\n");
    printf("optind:%d,opterr:%d\n",optind,opterr);
    printf("--------------------------\n");
       while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
       {
        printf("optind: %d\n", optind);
           switch (ch) 
        {
               case 'a':
                       printf("HAVE option: -a\n\n");   
                       break;
               case 'b':
                       printf("HAVE option: -b\n"); 
                       printf("The argument of -b is %s\n\n", optarg);
                       break;
               case 'c':
                       printf("HAVE option: -c\n");
                       printf("The argument of -c is %s\n\n", optarg);
                       break;
               case 'd':
                   printf("HAVE option: -d\n");
                     break;
              case 'e':
                    printf("HAVE option: -e\n");
                    printf("The argument of -e is %s\n\n", optarg);
                  break;
              case '?':
                       printf("Unknown option: %c\n",(char)optopt);
                       break;
               }
       }
    
       printf("----------------------------\n");
      printf("optind=%d,argv[%d]=%s\n",optind,optind,argv[optind]);

    printf("--------------------------\n");
    for(i=0;i<argc;i++)
    {
        printf("%s\n",argv[i]);
    }
    printf("--------------------------\n");
    

}

 命令行:./main zheng -b "qing er" han -c123 qing

输出结果为:

--------------------------
./main
zheng
-b
qing er
han
-c123
qing
--------------------------


optind:1,opterr:1
--------------------------
optind: 4
HAVE option: -b
The argument of -b is qing er

optind: 6
HAVE option: -c
The argument of -c is 123

----------------------------
optind=4,argv[4]=zheng
--------------------------
./main
-b
qing er
-c123
zheng
han
qing
--------------------------

可以看到最开始argv[]内容为:

./main
zheng
-b
qing er
han
-c123
qing

在执行了多次getopt后变成了

./main
-b
qing er
-c123
zheng
han
qing

我们看到,被getopt挑出的选项和对应的参数都按顺序放在了数组的前面,而那些既不是选项又不是参数的会按顺序放在后面。而此时optind为4,即指向第一个非选项也非选项的参数,zheng

花了40多分钟整理,希望能够给需要的人带来帮助。

很多时候我都在寻思,为啥要花时间整理,明明已经非常忙碌了,有这点时间休息一下多好,多惬意?

我总结的原因有一下几个:

1、总结时会注意到之前没有关注的问题,可以加深对问题的理解。

2、方便以后忘记的时候查阅

3、与广大朋友们分享,想想我们从哪些大牛的博客里得到的太多了。我们应当向那些大神学习。把自己学到的分享出来,帮助其他人(虽然我很渣,但是三人行必有我师,应该还是会帮到些人吧)。

共勉!努力!

最后给大家介绍一个写的更加全面的文章:http://blog.csdn.net/huangxiaohu_coder/article/details/7475156

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值