By experiment, it appears that I can can capture successive values of optarg
while iterating int getopt(int argc, char * const argv[], const char *optstring)
and reference them later, as in the following sample program:
// 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;
}
Compilation & example execution:
> gcc -g main.c && ./a.out -dabc -e def -a
d (0x7fffe8d1d2b2): [abc]
e (0x7fffe8d1d2b9): [def]
a ((nil)): []
(0x7fffe8d1d2b2): [abc]
(0x7fffe8d1d2b9): [def]
Question: Is this valid? I.e. are successive non-NULL optarg
values valid after successive iterations of getopt()
and/or its final iteration (when it returns -1)? I.e. is it safe to capture successive values and reference them later (i.e. without strdup
ing them)? I don't want to assume my experimental code is generally correct.
The man page states there is an extern char* optarg
but doesn't specify whether it may be reused by successive invocations of getopt()
.
(Since the arguments to getopt
are argc
and argv
, that implies that optarg
is set to offsets of argv
in which case I imagine it is safe to capture its successive values, but I'd like to learn if this is a correct surmise).
According to the POSIX specification of getopt
:
The getopt() function shall return the next option character (if one is found) from argv that matches a character in optstring, if there is one that matches. If the option takes an argument, getopt() shall set the variable optarg to point to the option-argument as follows:
If the option was the last character in the string pointed to by an element of argv, then optarg shall contain the next element of argv, and optind shall be incremented by 2. If the resulting value of optind is greater than argc, this indicates a missing option-argument, and getopt() shall return an error indication.
Otherwise, optarg shall point to the string following the option character in that element of argv, and optind shall be incremented by 1.
(Emphasis mine.)
This says optarg
always points into an element of argv
. It never makes a copy.
Since the elements of argv
are valid for as long as your program runs, your code is valid (no copying required).
NB. The POSIX page also shows an example of command line options with arguments that is essentially equivalent to your version:
char *ifile;
...
while ((c = getopt(argc, argv, ":abf:o:")) != -1) {
switch(c) {
...
case 'f':
ifile = optarg;
break;
...