C getopt_long()--使用它的正确方法?

C getopt_long()--使用它的正确方法?,c,C,好的,我已经搜索并找到了以下两个StackOverflow主题,它们让我朝着正确的方向前进: 注意:所有代码都是伪代码。工作时将发布可编译代码 但是,我仍然对如何在C中使用getopt_long()完全感到困惑。我正在编写的程序被定义为具有以下可能的标记(但可以包含您绝对需要的标记,用空值填充其余标记): 现在,根据我所读的,我需要为长选项使用一个struct,对吗?如果是这样的话,我写了一些类似的东西: struct fields field = { char *[] title;

好的,我已经搜索并找到了以下两个StackOverflow主题,它们让我朝着正确的方向前进:

注意:所有代码都是伪代码。工作时将发布可编译代码

但是,我仍然对如何在C中使用getopt_long()完全感到困惑。我正在编写的程序被定义为具有以下可能的标记(但可以包含您绝对需要的标记,用空值填充其余标记):

现在,根据我所读的,我需要为长选项使用一个struct,对吗?如果是这样的话,我写了一些类似的东西:

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);
从这里开始,我可以严格使用field struct并在程序中执行我需要的操作吗?然而,如果是这种情况,有人能解释整个long_options结构吗?我读了手册页之类的,我完全搞糊涂了。通过重新阅读手册页,我可以看到我可以将变量设置为null,并且应该将所有选项要求设置为“required_argument”?然后通过while()循环设置结构?然而,我看到optarg正在使用。这是由getopt_long()设置的吗?或者是示例中缺少了它

最后一个问题是,我总是有一个未命名的必需选项:filename,我会使用argv[0]来访问它吗?(因为我可以假设它将是第一个)


另一方面,这与家庭作业问题有关,但与解决问题无关,更重要的是,必须首先理解C中通过命令行传递和解析的参数。

首先,您可能不需要
0
,因为
has_arg
字段-它必须是
no_argument
中的一个,
必需参数
,或
可选参数
。在您的情况下,所有这些参数都将是
必需参数
。除此之外,您没有正确使用
标志
字段-它必须是一个整数指针。如果设置了相应的标志,
getopt_long()
将用通过
val
字段传入的整数填充它。我认为你根本不需要这个功能。以下是一个更好(缩短)的例子:

static struct option long_options[] =
{
    {"title", required_argument, NULL, 't'},
    {"artist", required_argument, NULL, 'a'},
    {NULL, 0, NULL, 0}
};
然后,您可以适当地使用它(直接从手册页,我添加了一些注释):

您可以根据需要扩展其他字段(请添加一些错误处理!)。注意-如果您想像在示例中一样使用
-title
-artist
,则需要使用
getopt_long_only()
,它没有短选项

至于您的
filename
选项,您将从
getopt_long()
调用中以
'?'
的形式获得它,这样您就可以在那时处理它了。您的其他选项是要求它是第一个或最后一个选项,并单独处理。

如果使用库,您将能够像在伪代码中那样创建一些智能的东西:

#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)
#包括
#包括“popt.h”
结构域{
字符*标题;
char*艺术家;
/*等*/
}场;
field.title=NULL;
field.artist=NULL;
/*以下是您在伪代码中想要的内容*/
结构poptOption选项表[]={
{“title”,'t',POPT_ARG_字符串,&field.title,'t'
“设置相册的“标题”},
{“artist”、'a',POPT_ARG_STRING,&field.artist,'a'
“设置专辑的“艺术家”},
POPT_自动帮助
POPT_桌面
};
poptContext optCon=poptGetContext(NULL,argc,argv,optionTable,0);
poptSetOtherOptionHelp(optCon,“[OPTIONS]”);
字符c;
而((c=poptGetNextOpt(optCon))>=0){
开关(c){
案例“t”:
/*只在你需要的时候做额外的事情*/
打破
案例“a”:
/*只在你需要的时候做额外的事情*/
打破
违约:
PoptRunsage(optCon,标准,0);
出口(1);
}
}
if(field.title)printf(“\n标题为[%s]”,field.title);
如果(field.artist)printf(“\n列表为[%s]”,field.artist)

比getopt更聪明;)

显示的结构定义无法编译。请提供可编译代码。
char*[]标题不是有效的声明。尝试
char*title[]
注意
&field.title
将返回一个
字符***
,这可能不是您想要的。请参阅getopt(3)和getopt_long(3)的手册页,它们都有示例。我收回了关于
&field.title
的部分。显然,它没问题(它是一个
char**
)。@JonathanLeffler,它不会基于它是一个结构的事实进行编译,还是我做错了什么?我对整个C语言还是比较陌生的。给出的例子使用了-title,所以我想getopt_long_only()将是我最好的选择。只是为了确保:我将做一个while循环并切换它们,然后在那里进行所有设置。这很有道理。在本例中,如何处理未命名变量?在我开始处理这些之前,使用argv[0]设置它?@Jeremy,如果你知道它总是第一个就可以了。不过,请确保将
argv+1
argc-1
传递给
getopt()
调用。您也可以在switch语句中的
大小写“?”
中处理它。它应该是“struct option”,而不是“struct options”@CarlNorum我对此有问题。由于long_选项(id3tage.c:30:warning:struct initializer id3tage.c:30:warning:(
long_options[0-6]”接近初始化),我收到了一系列警告,错误:id3tage.c:28:error:“long_options”的存储大小未知;id3tage.c:30:error:
required_参数”未声明(首次在此函数中使用);ID3tage.c:20:error:在
title set'的声明中有两个或多个数据类型;ID3tage.c:28:error:数组元素
long_options'的类型不完整有什么想法吗?我将发布一些完整的代码并链接到您。您需要包括
getopt.h
// 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;
    }
}
#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)