博客專欄

EEPW首頁 > 博客 > 命令行選項(xiàng)解析函數(shù)(C語言):getopt()和getopt_long()

命令行選項(xiàng)解析函數(shù)(C語言):getopt()和getopt_long()

發(fā)布人:電子禪石 時間:2019-12-12 來源:工程師 發(fā)布文章


上午在看源碼項(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命令手冊:

復(fù)制代碼
復(fù)制代碼
#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;
復(fù)制代碼
復(fù)制代碼

先拿最簡單的 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í)例:

復(fù)制代碼
復(fù)制代碼
#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]);
    }  
}
復(fù)制代碼
復(fù)制代碼

編譯上述程序并執(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í)例:

復(fù)制代碼
復(fù)制代碼
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);
    }  
}
復(fù)制代碼
復(fù)制代碼

編譯上述程序并執(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)文章:晶體管原理


關(guān)鍵詞:

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉