2011-09-20 43 views
13

OK,我已搜查,發現我開始在正確的方向以下兩個StackOverflow的主題:getopt_long() - 使用它的正確方法?

Argument-parsing helpers for C/UNIX

Pass arguments into C program from command line

注意:所有代碼是僞代碼。它會在可編程代碼發佈後運行。

但是,我仍然完全困惑於如何在C中使用getopt_long()。我正在編寫的程序被定義爲具有以下可能的標記(但可以包括儘可能多的,你絕對需要的,填補其餘在空值):

id3tagEd filename -title "title" -artist "artist" -year 1991 -comment "comment" -album "album" -track 1 

現在,從我讀的,我需要利用一個結構的長選項,正確的?如果是這樣,我沿着這行寫的東西:

struct fields field = 
{ 
    char *[] title; 
    char *[] artist; 
    char *[] album; 
    int year; 
    char *[] comment; 
    int track; 
} 


static struct options long_options[] = 
{ 
    {"title", 0, &field.title, 't'}, 
    {"artist", 0, &field.artist, 'a'}, 
    {"album", 0, &field.album, 'b'}, 
    {"year", 0, &field.year, 'y'}, 
    {"comment", 0, &field.comment, 'c'}, 
    {"track", 0, &field.track, 'u'}, 
    {0, 0, 0, 0} 
} 

現在,從我收集,我將通過這個稱之爲:

int option_index = 0; 

int values = getopt_long(argc, argv, "tabycu", long_options, &option_index); 

從這裏,我能嚴格使用字段結構和做我需要在我的程序內?但是,如果是這樣的話,有人可以解釋整個long_options結構嗎?我閱讀手冊頁等,而我只是完全困惑。通過重讀手冊頁,我可以看到我可以將變量設置爲null,並且應該將我的所有選項要求設置爲「required_argument」?然後通過while()循環設置結構?但是,我看到使用了optarg。這是由getopt_long()設置的嗎?還是從示例中缺失?

最後一個問題,我將始終有一個未命名的必需選項:文件名,我只是使用argv [0]來獲得訪問權限? (因爲我可以認爲它會是第一個)。

在附註中,這與作業問題有關,但它與解決它無關,它更基本,必須先通過命令行理解C中的參數傳遞和解析。

+0

所示的結構定義不會編譯。請提供可編譯的代碼。 –

+0

'char * [] title;'不是有效的聲明。嘗試'char * title [];'請注意'&field.title'會返回一個'char ***',這可能不是你想要的。 –

+1

查看getopt(3)和getopt_long(3)的手冊頁,兩者都有示例。 –

回答

22

首先,你可能不希望0has_arg場 - 它必須是一個no_argumentrequired_arguemnt,或optional_argument。在你的情況下,他們都將是required_argument。除此之外,你沒有正確使用flag字段 - 它必須是一個整數指針。如果設置了相應的標誌,則getopt_long()將使用您通過val字段傳入的整數進行填充。我認爲你根本不需要這個功能。這裏有一個更好的(縮短)例如,對於您的情況:

static struct option long_options[] = 
{ 
    {"title", required_argument, NULL, 't'}, 
    {"artist", required_argument, NULL, 'a'}, 
    {NULL, 0, NULL, 0} 
}; 

後來的後來,你可以適當地使用它(直接從手冊頁,我加入了一些註釋):

// loop over all of the options 
while ((ch = getopt_long(argc, argv, "t:a:", long_options, NULL)) != -1) 
{ 
    // check to see if a single character or long option came through 
    switch (ch) 
    { 
     // short option 't' 
     case 't': 
      field.title = optarg; // or copy it if you want to 
      break; 
     // short option 'a' 
     case 'a': 
      field.artist = optarg; // or copy it if you want to 
      break; 
    } 
} 

您可以延長你的其他必要的字段(請添加一些錯誤處理!)。注意 - 如果您想使用-title-artist(如您在示例中所示),則需要使用getopt_long_only(),該選項不具有簡短選項。

至於你filename選項,你會得到了從getopt_long()呼叫'?',所以你可以在那個時候處理它。您的其他選擇是要求它是第一個或最後一個選項,並單獨處理它。

+0

給出的使用示例使用-title,所以我猜getopt_long_only()將是我最好的選擇。只是要確定:我會做一段時間循環並切換它們,並且盡我所能在那裏設置。這很有意義。在這個例子中,我將如何處理未命名的變量?在我開始處理它們之前,使用argv [0]來設置它? –

+0

@傑瑞米,是啊,如果你知道它將永遠是第一個會沒事的。不過,請務必將'argv + 1'和'argc-1'傳遞給'getopt()'調用。你也可以在switch語句中的'case'?''中處理它。 –

+0

它應該是「結構選項」,而不是「結構選項」 – Nikko

5

如果使用popt庫,你將能夠創建你在你的僞代碼做了一件聰明:

#include <stdio.h> 
#include "popt.h" 

struct _field { 
    char *title; 
    char *artist; 
    /* etc */ 
} field; 

field.title = NULL; 
field.artist = NULL; 

/* HERE IS WHAT YOU WANTED IN YOUR PSEUDO-CODE */ 
struct poptOption optionsTable[] = { 

    {"title", 't', POPT_ARG_STRING, &field.title, 't' 
    "set the 'title' of the album" }, 
    {"artist", 'a', POPT_ARG_STRING, &field.artist, 'a' 
    "set the 'artist' of the album" }, 
    POPT_AUTOHELP 
    POPT_TABLEEND 
}; 

poptContext optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); 
poptSetOtherOptionHelp(optCon, "[OPTIONS]"); 

char c; 
while ((c = poptGetNextOpt(optCon)) >= 0) { 
    switch (c) { 
     case 't': 
      /* do extra stuff only if you need */ 
      break; 
     case 'a': 
      /* do extra stuff only if you need */ 
      break; 
     default: 
      poptPrintUsage(optCon, stderr, 0); 
      exit(1); 
    } 
} 

if (field.title) printf("\nTitle is [%s]", field.title); 
if (field.artist) printf("\nArtist is [%s]", field.artist) 

要高於getopt的聰明;)