C语言 getopt_long()——正确的使用方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7489093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
getopt_long() -- proper way to use it?
提问by Jeremy Dentel
OK, I have searched and found the following two StackOverflow topics that started me in the right direction:
好的,我已经搜索并找到了以下两个 StackOverflow 主题,它们使我朝着正确的方向前进:
Argument-parsing helpers for C/UNIX
Pass arguments into C program from command line
NOTE: ALL CODE IS PSEUDO-CODE. WILL POST COMPILABLE CODE WHEN IT WORKS.
注意:所有代码都是伪代码。当它工作时将发布可编译的代码。
However, I'm still completely confused on how to use getopt_long() in C. The program I'm writing is defined as having the following possible tags (but can include as many as you absolutely need, filling the rest in with empty values):
但是,我仍然对如何在 C 中使用 getopt_long() 感到困惑。我正在编写的程序被定义为具有以下可能的标签(但可以包含您绝对需要的标签,其余的用空值填充):
id3tagEd filename -title "title" -artist "artist" -year 1991 -comment "comment" -album "album" -track 1
Now, from what I read, I need to utilize a struct for the long options, correct? If so, I wrote something along the lines of this:
现在,从我读到的内容来看,我需要为长选项使用结构,对吗?如果是这样,我写了一些类似的东西:
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}
}
Now, from what I gathered, I would be calling it via this:
现在,根据我收集的信息,我将通过以下方式调用它:
int option_index = 0;
int values = getopt_long(argc, argv, "tabycu", long_options, &option_index);
From here, could I strictly use the field struct and do what I need to within my program? However, if this is the case, can someone explain the whole long_options struct? I read the man pages and such, and I'm just utterly confused. By rereading the man pages, I can see I can set variables to null, and should be setting all my option requirements to "required_argument"? And then setting the structs via a while() loop? However, I see optarg being used. Is this set by getopt_long()? Or is it missing from the example?
从这里开始,我可以严格使用字段结构并在我的程序中做我需要做的事情吗?但是,如果是这种情况,有人可以解释整个 long_options 结构吗?我阅读了手册页之类的内容,我完全糊涂了。通过重新阅读手册页,我可以看到我可以将变量设置为空,并且应该将所有选项要求设置为“required_argument”?然后通过 while() 循环设置结构?但是,我看到正在使用 optarg。这是由 getopt_long() 设置的吗?还是示例中缺少它?
And one last issue, I will always have an unnamed required option: filename, would I just use argv[0] to gain access to that? (Since I can assume it'll be first).
最后一个问题,我总是有一个未命名的必需选项:文件名,我是否只使用 argv[0] 来访问它?(因为我可以假设它会是第一个)。
On a side note, this is related to a homework problem, but it has nothing to do with fixing it, its more of a fundamental, have to understand argument passing and parsing in C via command line first.
附带说明一下,这与作业问题有关,但与修复它无关,它更重要的是必须首先通过命令行了解 C 中的参数传递和解析。
回答by Carl Norum
First off, you probably don't want 0for the has_argfield - it must be one of no_argument, required_arguemnt, or optional_argument. In your case, all of them are going to be required_argument. Besides that, you're not using the flagfield correctly - it has to be an integer pointer. If the corresponding flag is set, getopt_long()will fill it in with the integer you passed in via the valfield. I don't think you need this feature at all. Here's a better (shortened) example for your case:
首先,你可能不希望0的has_arg领域-它必须是一个no_argument,required_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}
};
Then later, you can use it appropriately (straight from the manpage, I added some comments):
然后,您可以适当地使用它(直接从联机帮助页,我添加了一些评论):
// 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;
}
}
You can extend for your other fields as necessary (and add some error handling, please!). Note - if you want to use -titleand -artistlike you have in your example, you'll need to use getopt_long_only(), which doesn't have short options.
您可以根据需要扩展其他字段(请添加一些错误处理!)。注意 - 如果您想在示例中使用-title并-artist像您一样使用getopt_long_only(),则需要使用,它没有简短的选项。
As to your filenameoption, you'll get that out as a '?'from the getopt_long()call, so you could handle it at that time. Your other options are to require that it is either the first or the last option and handle it by itself separately.
至于你的filename选择,你会'?'从getopt_long()电话中得到它,所以你可以在那个时候处理它。您的其他选项是要求它是第一个或最后一个选项并单独处理它。
回答by user1823890
If you use the poptlibrary, you will be able to create something smart as you did in your pseudo-code:
如果您使用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)
Be smart than getopt ;)
比 getopt 聪明 ;)

