在实际argv上使用getopt()
机制后,我将其瞄准我自己的类argv数组。接口是不可重入的(保持状态(,并且各种实现以不同的方式重置。
- 在XPG3/SVID中,它是
optreset = 1;
(freebsd,macosx( - XPG4/POSIX/SUS是
optind = 1;
- 在Linux/GLIBC中,它也是
optind = 0;
(debian(
我不想仅仅为此自动配置。
什么是一组可靠的#ifdef
?
唯一的标准是设置optind = 1
。
SUSv4标准没有提及optreset
,并声明optind = 0
"未指定":
如果应用程序在调用
getopt()
之前将optind
设置为零,则行为未指定。
否则,标准会变得模糊,并且根本不会说明多次调用getopt()
,既不允许也不声明它未定义。
此外,没有定义optind = 0
或optreset
是否受支持(fwiw前者在OpenBSD上受支持,但在FreeBSD上不受支持,后者在Linux/musl上受支持但在Linux/glibc上不受欢迎(,因此没有任何可靠的方法可以通过#ifdef
s检测它。
在花哨的getopt/_long
实现中,我们不存在错误(见下文(,只要设置optind = 1
以重新启动getopt()
,只要
a(您不使用任何GNU扩展:
扫描多个参数向量或重新扫描相同参数向量的程序vector不止一次,并希望使用GNU扩展,例如在optstring开始时使用
+
和-
,或更改扫描之间的POSIXLY_CORRECT
,必须通过重置重新初始化getopt()
optind
至0
,
b(在返回-1
之前,您不会在中间重新启动getopt()
。例如,来自FreeBSD的getopt
:
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
...
int
getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
...
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
...
place = EMSG;
return (-1);
...
place = EMSG;
return (-1);
...
place = EMSG;
if (strchr(ostr, '-') == NULL)
return (-1);
...
return (BADCH);
...
return (BADARG);
...
return (BADCH);
...
return (optopt); /* return option letter */
}
Bugs
即使在返回-1
之后,getopt
的glibc实现也将保持陈旧状态。如果释放旧字符串,这可能会导致愚蠢的错误和崩溃。
OpenBSD实现也会这样做,但仅当使用伪造的-
选项时,如在getopt("q", ["prog", "-q-", NULL])
中。请注意,OpenBSD的getopt_long
实现可能已经作为默认的getopt()
进入了Solaris和Android等其他系统。