optarg值在对getopt的连续调用中是否持久?

时间:2018-11-27 20:35:18

标签: c getopt

通过实验,看来我可以在迭代optarg的同时捕获int getopt(int argc, char * const argv[], const char *optstring)的连续值,并在以后引用它们,如以下示例程序所示:

// main.c

#include <stdio.h>
#include <unistd.h>

int main( int argc, char* argv[] )
{
  int opt;
  char o;
  char* a = NULL;
  char* b = NULL;

  while ( -1 != ( opt = getopt( argc, argv, "abcd:e:" ) ) )
  {
    char o = opt & 0xFF;

    switch ( o )
    {
      case 'a':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        break;
      }
      case 'b':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        break;
      }
      case 'c':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        break;
      }
      case 'd':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        a = optarg;
        break;
      }
      case 'e':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        b = optarg;
        break;
      }
    }
  }

  printf( "(%p): [%s]\n", a, (NULL == a ? "" : a ) );
  printf( "(%p): [%s]\n", b, (NULL == b ? "" : b ) );

  return 0;
}

编译和示例执行:

> gcc -g main.c && ./a.out -dabc -e def -a
d (0x7fffe8d1d2b2): [abc]
e (0x7fffe8d1d2b9): [def]
a ((nil)): []
(0x7fffe8d1d2b2): [abc]
(0x7fffe8d1d2b9): [def]

问题:这有效吗?即在optarg的连续迭代和/或其最终迭代(返回-1时)之后,连续的非NULL getopt()值是否有效?即捕获连续的值并在以后引用它们(即不strdup对其进行引用)是否安全?我不想假设我的实验代码通常是正确的。

该手册页指出存在一个 extern char* optarg,但未指定是否可以通过连续调用getopt()来重用。

(由于getopt的参数是argcargv,这意味着将optarg设置为argv的偏移量,在这种情况下,我可以想象它可以安全地捕获其连续值,但是我想了解这是否是正确的假设)。

2 个答案:

答案 0 :(得分:3)

根据POSIX specification of getopt

  

getopt ()函数应从 argv 返回与 optstring 中的字符匹配的下一个选项字符(如果找到)。如果有一个匹配。如果选项带有参数,则 getopt ()应将变量 optarg 设置为指向选项参数,如下所示:

     
      
  1. 如果选项是 argv 元素指向的字符串中的最后一个字符,则 optarg 应包含< em> argv optind 应加2。如果 optind 的结果值大于 argc ,这表明缺少选项参数,并且 getopt ()将返回错误指示。

  2.   
  3. 否则, optarg 将指向 argv 的该元素中选项字符之后的字符串,并指向 optind 应增加1。

  4.   

(强调我的。)

这表示optarg始终指向argv的元素。它永远不会复制。

由于argv的元素在程序运行期间一直有效,因此您的代码有效(无需复制)。


NB。 POSIX页面上还显示了一个example of command line options with arguments,它基本上与您的版本等效:

char *ifile;
...
while ((c = getopt(argc, argv, ":abf:o:")) != -1) {
    switch(c) {
    ...
    case 'f':
        ifile = optarg;
        break;
    ...

答案 1 :(得分:0)

getopt状态的手册页:

  

optstring是包含合法选项字符的字符串。如果          此类字符后接冒号,该选项需要一个参数-          ,因此getopt()将指针指向以下文本          optv中的argv-element或以下argv-element的文本

还有:

  

默认情况下,getopt()会在扫描时置换argv的内容,以便          最终所有非选项都在末尾。

这意味着,它不会分配任何内存,也不会将文本存储在静态缓冲区中,而是直接在您提供的argv指针数组上工作,仅在其中提供地址。

您可以在代码中验证此行为:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv) {

    int opt, cur;

    while (-1 != (opt = getopt(argc, argv, "a:b:c:"))) {
        cur = optind - 1;
        printf("current elemnt = %d argv[%d] = %p optarg = %p delta = %d\n",
            cur, cur, argv[cur], optarg, (int)(optarg - argv[cur]));
    }

    return 0;
}