命令行選項(xiàng)解析函數(shù)(C語言):getopt()和getopt_long()
上午在看源碼項(xiàng)目 webbench 時,剛開始就被一個似乎挺陌生函數(shù) getopt_long() 給卡住了,說實(shí)話這函數(shù)沒怎么見過,自然不知道這哥們是干什么的。于是乎百度了一番,原來是處理命令行選項(xiàng)參數(shù)的,的確,正規(guī)點(diǎn)的大型程序一般第一步就是處理命令行參數(shù)的,接著才是主干程序。在百度和 man 的幫助下,找到了具體使用方法和解釋,二話不說趕緊學(xué)習(xí)一下,并總結(jié)出文檔記錄一下。
平時在寫程序時常常需要對命令行參數(shù)進(jìn)行處理,因?yàn)閰?shù)少,自己解析就可以搞定;如果命令行個數(shù)比較多時,如果按照順序一個一個定義參數(shù)含義很容易造成混亂,而且如果程序只按順序處理參數(shù)的話,一些“可選參數(shù)”的功能將很難實(shí)現(xiàn),這個問題在 linux 中用 getopt 等函數(shù)可以優(yōu)雅地解決。
一、查詢linux命令手冊:
#include<unistd.h> #include<getopt.h> /*所在頭文件 */ int getopt(intargc, char * const argv[], const char *optstring); int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int*longindex); int getopt_long_only(int argc, char * const argv[],const char *optstring, const struct option *longopts, int*longindex); extern char *optarg; /*系統(tǒng)聲明的全局變量 */ extern int optind, opterr, optopt;
先拿最簡單的 getopt 函數(shù)開刀,getopt_long 只是前者的增強(qiáng)版,功能多點(diǎn)而已。
二、getopt函數(shù)
1、定義:
int getopt(int argc, char * const argv[], const char *optstring);
2、描述:
getopt是用來解析命令行選項(xiàng)參數(shù)的,但是只能解析短選項(xiàng): -d 100,不能解析長選項(xiàng):--prefix
3、參數(shù):
argc:main()函數(shù)傳遞過來的參數(shù)的個數(shù) argv:main()函數(shù)傳遞過來的參數(shù)的字符串指針數(shù)組 optstring:選項(xiàng)字符串,告知 getopt()可以處理哪個選項(xiàng)以及哪個選項(xiàng)需要參數(shù)
4、返回:
如果選項(xiàng)成功找到,返回選項(xiàng)字母;如果所有命令行選項(xiàng)都解析完畢,返回 -1;如果遇到選項(xiàng)字符不在 optstring 中,返回字符 '?';如果遇到丟失參數(shù),那么返回值依賴于 optstring 中第一個字符,如果第一個字符是 ':' 則返回':',否則返回'?'并提示出錯誤信息。
5、下邊重點(diǎn)舉例說明optstring的格式意義:
char*optstring = “ab:c::”; 單個字符a 表示選項(xiàng)a沒有參數(shù) 格式:-a即可,不加參數(shù) 單字符加冒號b: 表示選項(xiàng)b有且必須加參數(shù) 格式:-b 100或-b100,但-b=100錯 單字符加2冒號c:: 表示選項(xiàng)c可以有,也可以無 格式:-c200,其它格式錯誤
上面這個 optstring 在傳入之后,getopt 函數(shù)將依次檢查命令行是否指定了 -a, -b, -c(這需要多次調(diào)用 getopt 函數(shù),直到其返回-1),當(dāng)檢查到上面某一個參數(shù)被指定時,函數(shù)會返回被指定的參數(shù)名稱(即該字母)
optarg —— 指向當(dāng)前選項(xiàng)參數(shù)(如果有)的指針。 optind —— 再次調(diào)用 getopt() 時的下一個 argv指針的索引。 optopt —— 最后一個未知選項(xiàng)。 opterr -—— 如果不希望getopt()打印出錯信息,則只要將全域變量opterr設(shè)為0即可。
以上描述的并不生動,下邊結(jié)合實(shí)例來理解:
6、實(shí)例:
#include<stdio.h> #include<unistd.h> #include<getopt.h> int main(intargc, char *argv[]) { int opt; char *string = "a::b:c:d"; while ((opt = getopt(argc, argv, string))!= -1) { printf("opt = %c\t\t", opt); printf("optarg = %s\t\t",optarg); printf("optind = %d\t\t",optind); printf("argv[optind] = %s\n",argv[optind]); } }
編譯上述程序并執(zhí)行結(jié)果:
輸入選項(xiàng)及參數(shù)正確的情況
dzlab:~/test/test#./opt -a100 -b 200 -c 300 -d opt = a optarg = 100 optind = 2 argv[optind] = -b opt = b optarg = 200 optind = 4 argv[optind] = -c opt = c optarg = 300 optind = 6 argv[optind] = -d opt = d optarg = (null) optind = 7 argv[optind] = (null)
或者這樣的選項(xiàng)格式(注意區(qū)別):
dzlab:~/test/test#./opt -a100 -b200 -c300 -d opt = a optarg = 100 optind = 2 argv[optind] = -b200 opt = b optarg = 200 optind = 3 argv[optind] = -c300 opt = c optarg = 300 optind = 4 argv[optind] = -d opt = d optarg = (null) optind = 5 argv[optind] = (null)
選項(xiàng)a是可選參數(shù),這里不帶參數(shù)也是正確的
dzlab:~/test/test#./opt -a -b 200 -c 300 -d opt = a optarg = (null) optind = 2 argv[optind] = -b opt = b optarg = 200 optind = 4 argv[optind] = -c opt = c optarg = 300 optind = 6 argv[optind] = -d opt = d optarg = (null) optind = 7 argv[optind] = (null)
輸入選項(xiàng)參數(shù)錯誤的情況
dzlab:~/test/test#./opt -a 100 -b 200 -c 300 -d opt = a optarg = (null) optind = 2 argv[optind] = 100 opt = b optarg = 200 optind = 5 argv[optind] = -c opt = c optarg = 300 optind = 7 argv[optind] = -d opt = d optarg = (null) optind = 8 argv[optind] = (null)
導(dǎo)致解析錯誤,第一個 optarg = null,實(shí)際輸入?yún)?shù) 100,由于格式不正確造成的(可選參數(shù)格式固定)
參數(shù)丟失,也會導(dǎo)致錯誤,c選項(xiàng)是必須有參數(shù)的,不加參數(shù)提示錯誤如下:
dzlab:~/test/test#./opt -a -b 200 -c opt = a optarg = (null) optind = 2 argv[optind] = -b opt = b optarg = 200 optind = 4 argv[optind] = -c ./opt: optionrequires an argument -- 'c' opt = ? optarg = (null) optind = 5 argv[optind] = (null)
這種情況,optstring 中第一個字母不是':',如果在 optstring 中第一個字母加':',則最后丟失參數(shù)的那個選項(xiàng) opt 返回的是':',不是'?',并且沒有提示錯誤信息,這里不再列出。
命令行選項(xiàng)未定義,-e選項(xiàng)未在optstring中定義,會報錯:
dzlab:~/test/test#./opt -a -b 200 -e opt = a optarg = (null) optind = 2 argv[optind] = -b opt = b optarg = 200 optind = 4 argv[optind] = -e ./opt: invalidoption -- 'e' opt = ? optarg = (null) optind = 5 argv[optind] = (null)
到這里應(yīng)該已經(jīng)把getopt函數(shù)的功能講解清楚了吧,下邊來說說 getopt_long 函數(shù),getopt_long 函數(shù)包含了 getopt 函數(shù)的功能,并且還可以指定"長參數(shù)"(或者說長選項(xiàng)),與 getopt 函數(shù)對比,getopt_long 比其多了兩個參數(shù):
三、getopt_long函數(shù)
1、定義:
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts,int *longindex);
2、描述:
包含 getopt 功能,增加了解析長選項(xiàng)的功能如:--prefix --help
3、參數(shù):
longopts 指明了長參數(shù)的名稱和屬性 longindex 如果longindex非空,它指向的變量將記錄當(dāng)前找到參數(shù)符合longopts里的第幾個元素的描述,即是longopts的下標(biāo)值
4、返回:
對于短選項(xiàng),返回值同getopt函數(shù);對于長選項(xiàng),如果flag是NULL,返回val,否則返回0;對于錯誤情況返回值同getopt函數(shù)
5、struct option
struct option { const char *name; /* 參數(shù)名稱 */ int has_arg; /* 指明是否帶有參數(shù) */ int *flag; /* flag=NULL時,返回value;不為空時,*flag=val,返回0 */ int val; /* 用于指定函數(shù)找到選項(xiàng)的返回值或flag非空時指定*flag的值 */ };
6、參數(shù)說明:
has_arg 指明是否帶參數(shù)值,其數(shù)值可選: no_argument 表明長選項(xiàng)不帶參數(shù),如:--name, --help required_argument 表明長選項(xiàng)必須帶參數(shù),如:--prefix /root或 --prefix=/root optional_argument 表明長選項(xiàng)的參數(shù)是可選的,如:--help或 –prefix=/root,其它都是錯誤
接著看一下實(shí)例操作會更加深刻地理解:
7、實(shí)例:
int main(intargc, char *argv[]) { int opt; int digit_optind = 0; int option_index = 0; char *string = "a::b:c:d"; static struct option long_options[] = { {"reqarg", required_argument,NULL, 'r'}, {"optarg", optional_argument,NULL, 'o'}, {"noarg", no_argument, NULL,'n'}, {NULL, 0, NULL, 0}, }; while((opt =getopt_long_only(argc,argv,string,long_options,&option_index))!= -1) { printf("opt = %c\t\t", opt); printf("optarg = %s\t\t",optarg); printf("optind = %d\t\t",optind); printf("argv[optind] =%s\t\t", argv[optind]); printf("option_index = %d\n",option_index); } }
編譯上述程序并執(zhí)行結(jié)果:
正確輸入長選項(xiàng)的情況
dzlab:~/test/test#./long --reqarg 100 --optarg=200 --noarg opt = r optarg =100 optind = 3 argv[optind] = --optarg=200 option_index = 0 opt = o optarg =200 optind = 4 argv[optind] = --noarg option_index = 1 opt = n optarg =(null) optind = 5 argv[optind] =(null) option_index = 2
或者這種方式:
dzlab:~/test/test#./long –reqarg=100 --optarg=200 --noarg opt = r optarg =100 optind = 2 argv[optind] = --optarg=200 option_index = 0 opt = o optarg =200 optind = 3 argv[optind] = --noarg option_index = 1 opt = n optarg =(null) optind = 4 argv[optind] =(null) option_index = 2
可選選項(xiàng)可以不給參數(shù)
dzlab:~/test/test#./long --reqarg 100 --optarg --noarg opt = r optarg =100 optind = 3 argv[optind] = --optarg option_index = 0 opt = o optarg =(null) optind = 4 argv[optind] =--noarg option_index = 1 opt = n optarg =(null) optind = 5 argv[optind] =(null) option_index = 2
輸入長選項(xiàng)錯誤的情況
dzlab:~/test/test#./long --reqarg 100 --optarg 200 --noarg opt = r optarg =100 optind = 3 argv[optind] = --optarg option_index= 0 opt = o optarg =(null) optind = 4 argv[optind] =200 option_index = 1 opt = n optarg =(null) optind = 6 argv[optind] =(null) option_index = 2
這時,雖然沒有報錯,但是第二項(xiàng)中 optarg 參數(shù)沒有正確解析出來(格式應(yīng)該是 —optarg=200)
必須指定參數(shù)的選項(xiàng),如果不給參數(shù),同樣解析錯誤如下:
dzlab:~/test/test#./long --reqarg --optarg=200 --noarg opt = r optarg =--optarg=200 optind = 3 argv[optind] =--noarg option_index = 0 opt = n optarg =(null) optind = 4 argv[optind] =(null) option_index = 2
長選項(xiàng)的舉例說明暫且就這么多吧,其它如選項(xiàng)錯誤、缺參數(shù)、格式不正確的情況自己再試驗(yàn)一下。
四、getopt_long_only函數(shù)
getopt_long_only 函數(shù)與 getopt_long 函數(shù)使用相同的參數(shù)表,在功能上基本一致,只是 getopt_long 只將 --name 當(dāng)作長參數(shù),但 getopt_long_only 會將 --name 和 -name 兩種選項(xiàng)都當(dāng)作長參數(shù)來匹配。getopt_long_only 如果選項(xiàng) -name 不能在 longopts 中匹配,但能匹配一個短選項(xiàng),它就會解析為短選項(xiàng)。
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點(diǎn),如有侵權(quán)請聯(lián)系工作人員刪除。
晶體管相關(guān)文章:晶體管工作原理
晶體管相關(guān)文章:晶體管原理