重置 getopt() 的便携式方法是什么?



在实际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 = 0optreset是否受支持(fwiw前者在OpenBSD上受支持,但在FreeBSD上不受支持,后者在Linux/musl上受支持但在Linux/glibc上不受欢迎(,因此没有任何可靠的方法可以通过#ifdefs检测它。

在花哨的getopt/_long实现中,我们不存在错误(见下文(,只要设置optind = 1以重新启动getopt(),只要

a(您不使用任何GNU扩展:

扫描多个参数向量或重新扫描相同参数向量的程序vector不止一次,并希望使用GNU扩展,例如在optstring开始时使用+-,或更改扫描之间的POSIXLY_CORRECT,必须通过重置重新初始化getopt()optind0

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等其他系统。

相关内容

最新更新