2

在真正的 argv 上使用它之后,我将机器瞄准getopt()我自己的类似 argv 的阵列。该接口是不可重入的(保持状态),并且各种实现以不同的方式重置。

  • 在 XPG3/SVID 中是optreset = 1;(freebsd, macosx)
  • 在 XPG4/POSIX/SUS 中是optind = 1;(suse tumbleweed)
  • 在 Linux/GLIBC 它也是optind = 0;(debian)

我不想仅仅为此而自动配置。

什么是可靠的集合#ifdef

4

1 回答 1

0

唯一的标准就是设置optind = 1

SUSv4标准没有提及optreset并声明optind = 0“未指定”:

如果应用程序optind在调用之前设置为零getopt(),则行为未指定。

否则,它的标准就含糊不清,根本没有说任何关于getopt()多次调用的事情,既不允许它也没有声明它未定义。

此外,没有定义说是否支持optind = 0optreset支持(fwiw 前者在 OpenBSD 上受支持,但在 FreeBSD 上不支持,后者在 Linux/musl 上,但在 Linux/glibc 上不支持),所以不可能有任何可靠的通过#ifdefs 检测它的方法。

不是针对花哨getopt/_long实现中的错误(见下文),只要设置optind = 1为重新启动就getopt()可以正常工作

a)你不使用任何GNU 扩展

扫描多个参数向量或多次重新扫描同一向量的程序,并希望在 optstring 的开头 使用 GNU 扩展,例如 +和,或更改两次 扫描之间-POSIXLY_CORRECT的值,必须getopt()通过重置 optind0

b)getopt()在它返回之前,您不会在中间重新启动-1。例如。来自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 */
}

错误

即使在返回之后,glibc 的实现getopt也会保持陈旧状态-1。如果释放旧字符串,这可能会导致愚蠢的错误和崩溃。

OpenBSD 实现也会这样做,但在使用虚假-选项时,如getopt("q", ["prog", "-q-", NULL]). 请注意,OpenBSD 的getopt_long实现可能已经getopt()成为其他系统(如 Solaris 和 Android)的默认实现。

于 2020-03-02T07:59:15.200 回答