您好我想在我的程序中使用getopt
。到目前为止,它对于正确的输入是有效的,但是当我以错误的方式使用概要时:option requires an argument -- 's'
之后我得到了一个分段错误:
while((args = getopt(argc, argv, "ehs:")) != -1){
switch (args) {
case 'e':
if (options.opts[0] == 1)
error_exit(USAGE_ERROR, "option multiple times");
else
options.opts[0] = 1;
break;
case 'h':
if (options.opts[1] == 1)
error_exit(USAGE_ERROR, "option multiple times");
else
options.opts[1] = 1;
break;
case 's':
if (options.opts[2] == 2)
error_exit(USAGE_ERROR, "option multiple times");
else
options.opts[2] = 2;
char *saveptr;
if((options.word = strtok_r(optarg, ":", &saveptr)) == NULL)
error_exit(USAGE_ERROR, "WORD MISSING");
if((options.tag = strtok_r(NULL, ":", &saveptr)) == NULL)
error_exit(USAGE_ERROR, "TAG MISSING");
char *temp = NULL;
if((temp = strtok_r(NULL, ":", &saveptr)))
error_exit(USAGE_ERROR, "WORD and TAG already set!");
break;
case '?': //Never enters this case or default. WHY???
default:
error_exit(USAGE_ERROR, "");
break;
}
}
我希望你能帮我解决这个问题。
如果需要,这是我的Opt结构:
typedef struct Opt
{
int opts[3]; // e h s
char *word,
*tag;
} Opt;
答案 0 :(得分:2)
请了解如何创建MCVE(How to create a Minimal, Complete, and Verifiable Example?)或 SSCCE(Short, Self-Contained, Correct Example) - 两个相同基本想法的名称和链接。
与user3629249中的answer一样,我根据您展示的内容创建了一个测试程序,但无法找到问题。
goc.c
)#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct Opt
{
int opts[3]; // e h s
char *word,
*tag;
} Opt;
enum E_Numbers { USAGE_ERROR };
static void error_exit(enum E_Numbers e, const char *tag)
{
fprintf(stderr, "%d: %s\n", e, tag);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
Opt options = { { 0 }, 0, 0 };
int args;
while((args = getopt(argc, argv, "ehs:")) != -1){
switch (args) {
case 'e':
if (options.opts[0] == 1)
error_exit(USAGE_ERROR, "option multiple times");
else
options.opts[0] = 1;
break;
case 'h':
if (options.opts[1] == 1)
error_exit(USAGE_ERROR, "option multiple times");
else
options.opts[1] = 1;
break;
case 's':
if (options.opts[2] == 2)
error_exit(USAGE_ERROR, "option multiple times");
else
options.opts[2] = 2;
char *saveptr;
if((options.word = strtok_r(optarg, ":", &saveptr)) == NULL)
error_exit(USAGE_ERROR, "WORD MISSING");
if((options.tag = strtok_r(NULL, ":", &saveptr)) == NULL)
error_exit(USAGE_ERROR, "TAG MISSING");
char *temp = NULL;
if((temp = strtok_r(NULL, ":", &saveptr)))
error_exit(USAGE_ERROR, "WORD and TAG already set!");
break;
case '?': //Never enters this case or default. WHY???
default:
error_exit(USAGE_ERROR, "Unexpected option");
break;
}
}
printf("e = %d, h = %d, s = %d\n", options.opts[0], options.opts[1], options.opts[2]);
printf("word = <<%s>>\n", options.word ? options.word : "NULL");
printf("tag = <<%s>>\n", options.tag ? options.tag : "NULL");
return 0;
}
循环正文中唯一的变化是将"Unexpected option"
消息添加到error_exit()
(和default:
)代码中case '?':
的调用中。 / p>
$ ./goc
e = 0, h = 0, s = 0
word = <<NULL>>
tag = <<NULL>>
$ ./goc -h -e
e = 1, h = 1, s = 0
word = <<NULL>>
tag = <<NULL>>
$ ./goc -h -e -s abc:def
e = 1, h = 1, s = 2
word = <<abc>>
tag = <<def>>
$ ./goc -h -e -s abc
0: TAG MISSING
$ ./goc -h -e -s abc:def:
e = 1, h = 1, s = 2
word = <<abc>>
tag = <<def>>
$ ./goc -h -e -s abc:def:ghi
0: WORD and TAG already set!
$ ./goc -h -f -s abc:def:ghi
$ ./goc: illegal option -- f
0: Unexpected option
$ ./goc -a -b -c -d -e -f -h -e
./goc: illegal option -- a
0: Unexpected option
$ ./goc -s
./goc: option requires an argument -- s
0: Unexpected option
$ ./goc -s --
0: TAG MISSING
$ ./goc -s --:--
e = 0, h = 0, s = 2
word = <<-->>
tag = <<-->>
$ ./goc -s -- # Note this one!
0: TAG MISSING
$ ./goc -s --:
0: TAG MISSING
$ ./goc -s --:--
e = 0, h = 0, s = 2
word = <<-->>
tag = <<-->>
$ ./goc -s --::--
e = 0, h = 0, s = 2
word = <<-->>
tag = <<-->>
$ ./goc -s --::--::
e = 0, h = 0, s = 2
word = <<-->>
tag = <<-->>
$ ./goc -s --::--::--
0: WORD and TAG already set!
$
因为error_exit()
函数实际退出,所以我不会从单次运行中报告多个错误;第一个是致命的。
没有崩溃;没有意外的行为。我认为你的麻烦在其他地方。
为了记录,测试是在Mac OS X 10.10.3上使用GCC 5.1.0和Apple在平台上提供的标准getopt()
进行的。但是,我也希望Linux上也有同样的行为,以及我所使用的所有Unix平台。
答案 1 :(得分:1)
这是我用于测试的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
int main( int argc, char* argv[] )
{
int options[6] = {0};
int args;
while((args = getopt(argc, argv, "ehs:")) != -1)
{
switch (args)
{
case 'e':
if (options[0] == 1)
printf( "option 'e' can only be included once \n" );
else
options[0] = 1;
break;
case 'h':
if (options[1] == 1)
printf( "option 'h' can only be included once\n" );
else
options[1] = 1;
break;
case 's':
if (options[2] == 2)
printf( "option 's' can only be included once\n" );
else
options[2] = 2;
break;
case '?': //Never enters this case or default. WHY???
default:
printf( "unknown option encountered\n");
break;
}
}
}
这是我使用的命令行:(无标题是测试函数的名称)
./untitled -a -b -c -d -e -f -h -e
这是跑步的结果。
./untitled: invalid option -- 'a'
unknown option encountered
./untitled: invalid option -- 'b'
unknown option encountered
./untitled: invalid option -- 'c'
unknown option encountered
./untitled: invalid option -- 'd'
unknown option encountered
./untitled: invalid option -- 'f'
unknown option encountered
option 'e' can only be included once
由于测试工作完美,我怀疑问题出在代码的其他地方。
答案 2 :(得分:0)
选项字符串中的单个:
表示该选项需要一个agument,它是字符后面的其余参数,如果选项字符是单独的,则是下一个参数。在后一种情况下,optarg
被设置为参数列表中的下一个指针,如果没有下一个参数,它将为NULL。
因此,在看到虚假-s
选项后,getopt
将返回s
,然后您的代码将取消引用optarg
,这是一个NULL指针,导致段错误(实际上它将它传递给strtok_r
,然后继续解除未初始化的save
,导致同样的问题)。检查optarg
以确保s
选项代码中的值不为空。