【问题标题】:getopt_long() -- proper way to use it?getopt_long() - 使用它的正确方法?
【发布时间】:2011-11-21 06:59:42
【问题描述】:

好的,我搜索并发现以下两个 StackOverflow 主题让我朝着正确的方向前进:

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 中传递和解析的参数。

【问题讨论】:

  • 显示的结构定义不会编译。请提供可编译的代码。
  • char *[] title; 不是有效的声明。试试char *title[]; 请注意&field.title 将返回char***,这可能不是您想要的。
  • 查看 getopt(3) 和 getopt_long(3) 的手册页,都有示例。
  • 我收回关于&field.title 的那一点。显然没关系(这是char**)。
  • @JonathanLeffler,它不会因为它是一个结构而编译,还是我做错了什么?我对整个 C 语言还是比较陌生。

标签: c


【解决方案1】:

首先,您可能不希望 0 用于 has_arg 字段 - 它必须是 no_argumentrequired_arguemntoptional_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}
};

然后,您可以适当地使用它(直接来自手册页,我添加了一些 cmets):

// 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() 调用中将其作为'?' 取出,以便您可以在那时处理它。您的其他选项是要求它是第一个或最后一个选项并单独处理它。

【讨论】:

  • 给出的使用示例使用-title,所以我想getopt_long_only() 将是我最好的选择。只是为了确定:我会做一个while循环并切换它们,并在那里完成我的所有设置。这很有意义。在这个例子中我将如何处理未命名的变量?在我开始处理这些之前使用 argv[0] 设置它?
  • @Jeremy,是的,如果你知道它总是第一个就好了。不过,请确保将 argv+1argc-1 传递给 getopt() 调用。您也可以在 switch 语句中的 case '?' 中处理它。
  • 应该是“struct option”而不是“struct options”
  • @CarlNorum 我遇到了这个问题。由于 long_options,我收到了一堆警告(id3tagEd.c:30:警告:结构初始化程序 id3tagEd.c:30 中的多余元素:警告:(long_options[0-6]'), and errors: id3tagEd.c:28: error: storage size of 'long_options' isn't known; id3tagEd.c:30: error: required_argument' 的近初始化未声明(在此函数中首次使用) ; id3tagEd.c:20: 错误:title set'; id3tagEd.c:28: error: elements of array long_options' 的声明中的两个或多个数据类型有不完整的类型有什么想法吗?我会在几个中发布完整的代码并链接你。
  • 您需要包含getopt.h
【解决方案2】:

如果您使用 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 聪明 ;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 2012-02-23
    • 2013-01-09
    相关资源
    最近更新 更多