- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一段代码来解析文本文件中的一些命令,我发现我认为这是 getopt 中的一个错误。只是想知道是否有人以前看过这个?
基本上我有一个循环,在每次迭代中我读取一个字符串,我用“strtok”将它转换为可以提供给 getopt 的东西并检查提供的选项。它在某些情况下有效:
$ ./test_short
cmd -ia
-- option i
-- option a
cmd -a
-- option a
cmd -i
-- option i
但它失败了,例如:
$ ./test_short
cmd -ia
-- option i
-- option a
cmd -i -a
cmd: invalid option -- '-'
-- option unknown
-- option a
-- option a
代码可以从https://github.com/angel-devicente/test-getopt中克隆出来,但为了完整起见,我也将简短选项放在下面。
是否知道这是一个真正的错误,还是有一些我忘记重置的其他全局变量?
谢谢,
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <string.h>
#include <unistd.h>
#define MAX_ARGS 10
#define MAX_C 100
int main(int argc, char **argv) {
int c;
char cmd[MAX_C+1];
int argc_i;
char *argv_i[MAX_ARGS];
while (1) {
// Read string, for example: cmd -i -a
fgets(cmd,MAX_C,stdin);
cmd[strlen(cmd) - 1] = 0;
if (strlen(cmd) <= 1) break;
// Transform into argc_i, argv_i, to feed to getopt
argc_i = 0;
char *p2 = strtok(cmd, " ");
while (p2 && argc_i < MAX_ARGS)
{
argv_i[(argc_i)++] = p2;
p2 = strtok(NULL, " ");
}
argv_i[argc_i] = 0;
// Reset getopt
optind = 1;
int option_index = 0;
while (1) {
c = getopt(argc_i, argv_i, "ia");
if (c == -1)
break;
switch (c) {
case 'a':
printf(" -- option a\n");
break;
case 'i':
printf(" -- option i\n");
break;
case '?':
printf(" -- option unknown\n");
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
printf("\n\n");
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
}
exit(EXIT_SUCCESS);
}
最佳答案
这看起来像是有意偏离 getopt
的 POSIX 规范。
首先,我更改了您代码中的这一行:
argv_i[(argc_i)++] = p2;
对此:
argv_i[(argc_i)++] = strdup(p2);
并将此添加到 while (1)
循环的末尾:
for (i=0;i<argc_i;i++) {
free(argv_i[i]);
}
并将其添加到顶部:
内存集(argv_i,0,sizeof(argv_i));
然后我运行了 valgrind:
==54748== Memcheck, a memory error detector
==54748== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==54748== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==54748== Command: ./x1
==54748==
optind=1
cmd -ia
arg 0: cmd
arg 1: -ia
-- option i
-- option a
cmd -i -a
==54748== Invalid read of size 1
==54748== at 0x4F192A1: _getopt_internal_r (in /usr/lib64/libc-2.17.so)
==54748== by 0x4F1A56A: _getopt_internal (in /usr/lib64/libc-2.17.so)
==54748== by 0x4F1A5B7: getopt (in /usr/lib64/libc-2.17.so)
==54748== by 0x400A2E: main (x1.c:48)
==54748== Address 0x5205093 is 3 bytes inside a block of size 4 free'd
==54748== at 0x4C2AF9D: free (vg_replace_malloc.c:540)
==54748== by 0x400B25: main (x1.c:89)
==54748== Block was alloc'd at
==54748== at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==54748== by 0x4EC3AA9: strdup (in /usr/lib64/libc-2.17.so)
==54748== by 0x400991: main (x1.c:31)
==54748==
-- option i
-- option a
由于在测试程序中没有对 malloc 内存的引用,这意味着 getopt
实现保留了一个指向它的指针。
现在让我们看一下 https://github.com/lattera/glibc/blob/master/posix/getopt.c 中的几行包括 _getopt_internal_r
:
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to 'getopt'.
On entry to 'getopt', zero means this is the first call; initialize.
When 'getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, 'optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* 1003.2 says this must be 1 before any call. */
int optind = 1;
...
static struct _getopt_data getopt_data;
...
int
_getopt_internal_r (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind,
int long_only, struct _getopt_data *d, int posixly_correct)
{
int print_errors = d->opterr;
if (argc < 1)
return -1;
d->optarg = NULL;
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct);
...
int
_getopt_internal (int argc, char **argv, const char *optstring,
const struct option *longopts, int *longind, int long_only,
int posixly_correct)
{
int result;
getopt_data.optind = optind;
getopt_data.opterr = opterr;
result = _getopt_internal_r (argc, argv, optstring, longopts,
longind, long_only, &getopt_data,
posixly_correct);
optind = getopt_data.optind;
optarg = getopt_data.optarg;
optopt = getopt_data.optopt;
return result;
}
#define GETOPT_ENTRY(NAME, POSIXLY_CORRECT) \
int \
NAME (int argc, char *const *argv, const char *optstring) \
{ \
return _getopt_internal (argc, (char **)argv, optstring, \
0, 0, 0, POSIXLY_CORRECT); \
}
#ifdef _LIBC
GETOPT_ENTRY(getopt, 0)
GETOPT_ENTRY(__posix_getopt, 1)
#else
GETOPT_ENTRY(getopt, 1)
#endif
在这里我们可以看到 optind
被初始化为 1 和一个未初始化的内部静态结构。还有一条评论说 “在进入 'getopt' 时,零表示这是第一个调用;初始化。” 表示不同的初始化条件。
getopt
调用 getopt_internal
,随后将 optind
分配给静态结构的相应成员,然后将其传递给 _getopt_internal_r
。 _getopt_internal_r
函数然后检查结构的 optind
成员是否为 0 或 __initialized
成员是否为 0,如果是,则初始化函数被调用,定义如下:
static const char *
_getopt_initialize (int argc _GL_UNUSED,
char **argv _GL_UNUSED, const char *optstring,
struct _getopt_data *d, int posixly_correct)
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
if (d->optind == 0)
d->optind = 1;
d->__first_nonopt = d->__last_nonopt = d->optind;
d->__nextchar = NULL;
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
d->__ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
d->__ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct || !!getenv ("POSIXLY_CORRECT"))
d->__ordering = REQUIRE_ORDER;
else
d->__ordering = PERMUTE;
d->__initialized = 1;
return optstring;
}
我们可以在这里看到,如果 optind
成员当前为 0,则该成员将被设置为 1。另外,请特别注意这一行:
d->__nextchar = NULL;
如果我们再看看 https://github.com/lattera/glibc/blob/master/posix/getopt_int.h在定义此字段的位置,我们看到以下内容:
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
char *__nextchar;
所以这个变量跟踪处理停止的地方。但是回到 _getopt_internal_r
if (d->optind == 0 || !d->__initialized)
optstring = _getopt_initialize (argc, argv, optstring, d, posixly_correct);
只有当 optind
为 0 时才会发生重置。
因此在此实现中,将optind
设置为0 将重置处理。然而,这不是可移植的,因为 POSIX 指定这样做是未指定的行为。
这意味着要么将此代码更改为将 optind == 1
作为初始化条件,要么更新文档以反射(reflect)与 POSIX 标准的这种偏差并声明这是一种偏差.
关于c - 非全局使用的 getopt (C) 错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65291405/
我的应用程序中有一个 settings.php 页面,它使用 $GLOBALS 来存储网络应用程序中使用的配置。 例如,他是我使用的一个示例设置变量: $GLOBALS["new_login_page
我正在尝试编译我们在 OS 类上获得的简单操作系统代码。它在 Ubuntu 下运行良好,但我想在 OS X 上编译它。我得到的错误是: [compiling] arch/i386/arch/start
我知道distcp无法使用通配符。 但是,我将需要在更改的目录上安排distcp。 (即,仅在星期一等“星期五”目录中复制数据),还从指定目录下的所有项目中复制数据。 是否有某种设计模式可用于编写此类
是否可以在config.groovy中全局定义资源格式(json,xml)的优先级,而不是在每个Resource上指定?例如,不要在@Resource Annotation的参数中指定它,例如: @R
是否有一些简单的方法来获取大对象图的所有关联,而不必“左连接获取”所有关联?我不能只告诉 Hibernate 默认获取 eager 关联吗? 最佳答案 即使有可能有一个全局 lazy=false(谷歌
我正在尝试实现一个全局加载对话框...我想调用一些静态函数来显示对话框和一些静态函数来关闭它。与此同时,我正在主线程或子线程中做一些工作...... 我尝试了以下操作,但对话框没有更新...最后一次,
当我偶然发现 this question 时,我正在阅读更改占位符文本。 无论如何,我回去学习了占位符。一个 SO 的回答大致如下: Be careful when designing your pl
例如,如果我有这样的文字: "hello800 more text 1234 and 567" 它应该匹配 1234 和 567,而不是 800(因为它遵循 hello 的 o,这不是一个数字)。 这
我一直在尝试寻找一种无需使用 SMS 验证系统即可验证电话号码(Android 和 iPhone)的方法。原因纯粹是围绕成本。我想要一个免费的解决方案。 我可以安全地假设 Android 操作系统会向
解决此类问题的规范 C++ 设计模式是什么? 我有一些共享多个类的多线程服务器。我需要为大多数类提供各种运行时参数(例如服务器名称、日志记录级别)。 在下面的伪 C++ 代码中,我使用了一个日志记录类
这个问题在这里已经有了答案: Using global variables in a function (25 个答案) 关闭 9 年前。 我是 python 的新手,所以可能有一个简单的答案,但我
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Does C++ call destructors for global and class static
我正在尝试使用 Objective-C 中的 ArrayList 的等价物。我知道我必须使用 NSMutableArray。我想要一个字符串列表 (NSString)。关键是我的列表应该可以从我类(c
今天刚开始学习 Android 开发,我找不到任何关于如何定义 Helper 类或将全局加载的函数集合的信息,我会能够在我创建的任何 Activity 中使用它们。 我的计划是创建(至少目前)2 个几
为什么这段代码有效: var = 0 def func(num): print num var = 1 if num != 0: func(num-1) fun
$GLOBALS["items"] = array('one', 'two', 'three', 'four', 'five' ,'six', 'seven'); $alter = &$GLOBALS
我想知道如何实现一个可以在任何地方使用您自己的设置的全局记录器: 我目前有一个自定义记录器类: class customLogger(logging.Logger): ... 该类位于一个单独的
我需要使用 React 测试库和 Jest 在我的测试中模拟不同的窗口大小。 目前我必须在每个测试文件中包含这个beforeAll: import matchMediaPolyfill from 'm
每次我遇到单例模式或任何静态类(即(几乎)只有静态成员的类)的实现时,我想知道这是否实际上不是一种黑客行为,因此只是为了设计而严重滥用类和实例的原则单个对象,而不是设计类和创建单个实例。对我来说,看起
这个问题在这里已经有了答案: Help understanding global flag in perl (2 个回答) 7年前关闭。 my $test = "There was once an\n
我是一名优秀的程序员,十分优秀!