命令行選項解析函數(C語言):getopt()和getopt_long()
上午在看源碼項目webbench時,剛開始就被一個似乎挺陌生函數getopt_long()給卡住了,說實話這函數沒怎麽見過,自然不知道這哥們是幹什麽的。於是乎百度了一番,原來是處理命令行選項參數的,的確,正規點的大型程序一般第一步就是處理命令行參數的,接著才是主幹程序。在百度和man的幫助下,找到了具體使用方法和解釋,二話不說趕緊學習一下,並總結出文檔記錄一下。
平時在寫程序時常常需要對命令行參數進行處理,因為參數少,自己解析就可以搞定;如果命令行個數比較多時,如果按照順序一個一個定義參數含義很容易造成混亂,而且如果程序只按順序處理參數的話,一些“可選參數”的功能將很難實現,這個問題在linux中用getopt等函數可以優雅地解決。
查詢linux命令手冊:man 3 getopt_long:
<span style="font-size:14px;">#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; /*系統聲明的全局變量 */ extern int optind, opterr, optopt;</span>
先拿最簡單的getopt函數開刀,getopt_long只是前者的增強版,功能多點而已。
(1) getopt函數
定義:int getopt(int argc, char * const argv[], const char *optstring);
描述:getopt是用來解析命令行選項參數的,但是只能解析短選項: -d 100,不能解析長選項:--prefix
參數:argc:main()函數傳遞過來的參數的個數
argv:main()函數傳遞過來的參數的字符串指針數組
optstring:選項字符串,告知 getopt()可以處理哪個選項以及哪個選項需要參數
返回:如果選項成功找到,返回選項字母;如果所有命令行選項都解析完畢,返回-1;如果遇到選項字符不在optstring中,返回字符’?’;如果遇到丟失參數,那麽返回值依賴於optstring中第一個字符,如果第一個字符是’:’則返回’:’,否則返回’?’並提示出錯誤信息。
下邊重點舉例說明optstring的格式意義:
char*optstring = “ab:c::”;
單個字符a 表示選項a沒有參數 格式:-a即可,不加參數
單字符加冒號b: 表示選項b有且必須加參數 格式:-b 100或-b100,但-b=100錯
單字符加2冒號c:: 表示選項c可以有,也可以無 格式:-c200,其它格式錯誤
上面這個optstring在傳入之後,getopt函數將依次檢查命令行是否指定了 -a, -b, -c(這需要多次調用getopt函數,直到其返回-1),當檢查到上面某一個參數被指定時,函數會返回被指定的參數名稱(即該字母)
optarg —— 指向當前選項參數(如果有)的指針。
optind —— 再次調用 getopt() 時的下一個 argv指針的索引。
optopt —— 最後一個未知選項。
opterr -—— 如果不希望getopt()打印出錯信息,則只要將全域變量opterr設為0即可。
以上描述的並不生動,下邊結合實例來理解:
實例:
<span style="font-size:14px;">#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]); } }</span>
編譯上述程序並執行結果:
1、輸入選項及參數正確的情況
<span style="font-size:14px;">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)</span>
或者這樣的選項格式(註意區別):
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)
選項a是可選參數,這裏不帶參數也是正確的
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)
2、輸入選項參數錯誤的情況
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)
導致解析錯誤,第一個optarg = null,實際輸入參數100,由於格式不正確造成的(可選參數格式固定)
參數丟失,也會導致錯誤,c選項是必須有參數的,不加參數提示錯誤如下:
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中第一個字母加’:’,則最後丟失參數的那個選項opt返回的是’:’,不是’?’,並且沒有提示錯誤信息,這裏不再列出。
命令行選項未定義,-e選項未在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)
到這裏應該已經把getopt函數的功能講解清楚了吧,下邊來說說getopt_long函數,getopt_long函數包含了getopt函數的功能,並且還可以指定“長參數”(或者說長選項),與getopt函數對比,getopt_long比其多了兩個參數:
(2) getopt_long函數
定義:int getopt_long(int argc, char * const argv[], const char *optstring,
const struct option *longopts,int *longindex);
描述:包含getopt功能,增加了解析長選項的功能如:--prefix --help
參數:longopts 指明了長參數的名稱和屬性
longindex 如果longindex非空,它指向的變量將記錄當前找到參數符合longopts裏的第幾個元素的描述,即是longopts的下標值
返回:對於短選項,返回值同getopt函數;對於長選項,如果flag是NULL,返回val,否則返回0;對於錯誤情況返回值同getopt函數
<span style="font-size:14px;">struct option {</span> const char *name; /* 參數名稱 */ int has_arg; /* 指明是否帶有參數 */ int *flag; /* flag=NULL時,返回value;不為空時,*flag=val,返回0 */ int val; /* 用於指定函數找到選項的返回值或flag非空時指定*flag的值 */ };
has_arg 指明是否帶參數值,其數值可選:
no_argument 表明長選項不帶參數,如:--name, --help
required_argument 表明長選項必須帶參數,如:--prefix /root或 --prefix=/root
optional_argument 表明長選項的參數是可選的,如:--help或 –prefix=/root,其它都是錯誤
接著看一下實例操作會更加深刻地理解:
實例:
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); } }
編譯上述程序並執行結果:
1、正確輸入長選項的情況
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
可選選項可以不給參數
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
2、輸入長選項錯誤的情況
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
這時,雖然沒有報錯,但是第二項中optarg參數沒有正確解析出來(格式應該是—optarg=200)
必須指定參數的選項,如果不給參數,同樣解析錯誤如下:
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
長選項的舉例說明暫且就這麽多吧,其它如選項錯誤、缺參數、格式不正確的情況自己再試驗一下。
(3) getopt_long_only函數
getopt_long_only函數與getopt_long函數使用相同的參數表,在功能上基本一致,只是 getopt_long只將--name當作長參數,但getopt_long_only會將--name和-name兩種選項都當作長參數來匹配。getopt_long_only如果選項-name不能在longopts中匹配,但能匹配一個短選項,它就會解析為短選項。
Tags: include 百度 option linux C語言
文章來源: