C/C++ getopt()函数的介绍及使用
函數(shù)原型:
int getopt(int argc,char * const argv[ ],const char * optstring);
前兩個參數(shù)大家不會陌生,沒錯,就是老大main函數(shù)的兩個參數(shù)!老大傳進(jìn)來的參數(shù)自然要有人接著!
第三個參數(shù)是個字符串,看名字,我們可以叫他選項(xiàng)字符串(后面會說明)
返回值為int類型,我們都知道char類型是可以轉(zhuǎn)換成int類型的,每個字符都有他所對應(yīng)的整型值,其實(shí)這個返回值返回的就是一個字符,什么字符呢,叫選項(xiàng)字符(姑且這么叫吧,后面會進(jìn)一步說明)
在此之前還要介紹他的幾個兄弟
小弟1:extern char* optarg;
小弟2:extern int optind;
小弟3:extern int opterr;
小弟4:extern int optopt;
- 小弟1是用來保存選項(xiàng)的參數(shù)的(先混個臉熟,后面有例子);
- 小弟2用來記錄下一個檢索位置;
- 小弟3表示的是是否將錯誤信息輸出到stderr,為0時表示不輸出,
- 小弟4表示不在選項(xiàng)字符串optstring中的選項(xiàng)(有點(diǎn)亂哈,后面會有例子)
問題1:選項(xiàng)到底是個什么鬼?
? ? ? ? 在linux下大家都用過這樣一條指令吧:gcc helloworld.c -o helloworld.out;?這條指令中的-o就是命令行的選項(xiàng),而后面的helloworld.out就是-o選項(xiàng)所攜帶的參數(shù)。當(dāng)然熟悉shell指令的人都知道(雖然我并不熟悉),有些選項(xiàng)是不用帶參數(shù)的,而這樣不帶參數(shù)的選項(xiàng)可以寫在一起(這一點(diǎn)在后面的例子中會用到,希望理解),比如說有兩個選項(xiàng)-c和-d,這兩個選項(xiàng)都不帶參數(shù)(而且明顯是好基友),那么他們是可以寫在一起,寫成-cd的。實(shí)際的例子:當(dāng)我們刪除一個文件夾時可以使用指令?rm 目錄名 -rf,本來-r表示遞歸刪除,就是刪除文件夾中所有的東西,-f表示不提示就立刻刪除,他們兩個都不帶參數(shù),這時他們就可以寫在一起。
問題2:選項(xiàng)字符串又是何方神圣?
? ? ? ? "a:b:cd::e",這就是一個選項(xiàng)字符串。對應(yīng)到命令行就是-a ,-b ,-c ,-d, -e 。冒號又是什么呢??冒號表示參數(shù),一個冒號就表示這個選項(xiàng)后面必須帶有參數(shù)(沒有帶參數(shù)會報錯哦),但是這個參數(shù)可以和選項(xiàng)連在一起寫,也可以用空格隔開,比如-a123 和-a ? 123(中間有空格) 都表示123是-a的參數(shù);兩個冒號的就表示這個選項(xiàng)的參數(shù)是可選的,即可以有參數(shù),也可以沒有參數(shù),但要注意有參數(shù)時,參數(shù)與選項(xiàng)之間不能有空格(有空格會報錯的哦),這一點(diǎn)和一個冒號時是有區(qū)別的。
好了,先給個代碼,然后再解釋吧。
#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;}}}編譯后命令行執(zhí)行:# ./main -b "qing er"
輸出結(jié)果為:
optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er
?
? ? ? ? 我們可以看到:optind和opterr的初始值都為1,前面提到過opterr非零表示產(chǎn)生的錯誤要輸出到stderr上。那么optind的初值為什么是1呢?
? ? ? ? 這就要涉及到main函數(shù)的那兩個參數(shù)了,argc表示參數(shù)的個數(shù),argv[]表示每個參數(shù)字符串,對于上面的輸出argc就為3,argv[]分別為: ./main 和 -b 和"qing er" ,實(shí)際上真正的參數(shù)是用第二個-b 開始,也就是argv[1],所以optind的初始值為1;
? ? ? ? 當(dāng)執(zhí)行g(shù)etopt()函數(shù)時,會依次掃描每一個命令行參數(shù)(從下標(biāo)1開始),第一個-b,是一個選項(xiàng),而且這個選項(xiàng)在選項(xiàng)字符串optstring中有,我們看到b后面有冒號,也就是b后面必須帶有參數(shù),而"qing er"就是他的參數(shù)。所以這個命令行是符合要求的。至于執(zhí)行后optind為什么是3,這是因?yàn)閛ptind是下一次進(jìn)行選項(xiàng)搜索的開始索引,也是說下一次getopt()函數(shù)要從argv[3]開始搜索。當(dāng)然,這個例子argv[3]已經(jīng)沒有了,此時getopt()函數(shù)就會返回-1。
再看一個輸入:
?./main -b "qing er" -c1234
輸出結(jié)果為:
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
? ? ? ? 對于這個過程會調(diào)用三次getopt()函數(shù),和第一個輸入一樣,是找到選項(xiàng)-b和他的參數(shù)"qing er",這時optind的值為3,也就意味著,下一次的getopt()要從argv[3]開始搜索,所以第二次調(diào)用getopt()函數(shù),找到選項(xiàng)-c和他的參數(shù)1234(選項(xiàng)和參數(shù)是連在一起的),由于-c1234寫在一起,所以他兩占一起占用argv[3],所以下次搜索從argv[4]開始,而argv[4]為空,這樣第三次調(diào)用getopt()函數(shù)就會返回-1,循環(huán)隨之結(jié)束。
接下來我們看一個錯誤的命令行輸入:?./main -z 123
輸出為:
optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 2
Unknown option: z
其中./main: invalid option -- 'z'就是輸出到stderr的錯誤輸出。如果把opterr設(shè)置為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
前面提到過不帶參數(shù)的選項(xiàng)可以寫在一起,所以當(dāng)getopt()找到-z的時候,發(fā)現(xiàn)在optstring 中沒有,這時候他就認(rèn)為h也是一個選項(xiàng),也就是-h和-z寫在一起了,依次類推,直到找到-e,發(fā)現(xiàn)optstring中有。
? ? ? ?
? ? ? ? 最后要說明一下,getopt()會改變argv[]中參數(shù)的順序。經(jīng)過多次getopt()后,argv[]中的選項(xiàng)和選項(xiàng)的參數(shù)會被放置在數(shù)組前面,而optind 會指向第一個非選項(xiàng)和參數(shù)的位置。看例子
#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
輸出結(jié)果為:
--------------------------
./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[]內(nèi)容為:
./main
zheng
-b
qing er
han
-c123
qing
?
在執(zhí)行了多次getopt后變成了
./main
-b
qing er
-c123
zheng
han
qing
? ? ? ? 我們看到,被getopt挑出的選項(xiàng)和對應(yīng)的參數(shù)都按順序放在了數(shù)組的前面,而那些既不是選項(xiàng)又不是參數(shù)的會按順序放在后面。而此時optind為4,即指向第一個非選項(xiàng)也非選項(xiàng)的參數(shù),zheng
總結(jié)
以上是生活随笔為你收集整理的C/C++ getopt()函数的介绍及使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 集合List、Set、Hash
- 下一篇: Python之struct介绍及详解(与