【main参数】main函数的参数|命令行参数
目录
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;
}
说明
主要参考以下博客:
博客三:使用 Qt 解析命令行参数
短选项名之 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
- 源代码名称:argagg
- 源代码网址:http://www.github.com/vietjtnguyen/argagg
- argagg源代码文档
- argagg源代码下载
下载地址2:GitHub - liangchaoxi/comand-line-Parameter-parser: A simple C++11 command line argument parser
- Git URL:
Git Clone代码到本地:git://www.github.com/vietjtnguyen/argagg.git
Subversion代码到本地:git clone http://www.github.com/vietjtnguyen/argagg
命令行参数聚合器$ 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_result
arg
将不存在,也就是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
参数是c
,foo
是位置参数-aobc foo
:-o
参数是bc
,foo
是位置参数-oabc foo
:-o
参数是abc
,foo
是位置参数
对于空白分隔参数,贪婪处理意味着下一个参数元素( 在
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