Basically getopt is returning -1 when I have a non option before the other options.

    n = atoi(argv[1]);

    while ((opt = getopt(argc, argv, "hi:o:")) != -1) {
        switch (opt) {
        case 'i':
            ifile = optarg; 
            break;
        case 'o':
            ofile = optarg; 
            break;
        case 'h':
            printf("...");
            break;
        default:
            printf("Invalid Option\n");
            exit(0);
        }
    }

example:

./a.out 22 -i infile -o outfile

This makes getopt return -1 and the switch statement never gets executed.

./a.out -i infile -o outfile

However this works, but I really would like the first option to be just a number, and not have to include another option for it.

I thought getopt was supposed to handle this case, but I could be wrong. Any help is appreciated!

有帮助吗?

解决方案

Universal solution

The simplest way around the problem presented is:

n = atoi(argv[1]);

argv[1] = argv[0];
++argv;
--argc;

while ((opt = getopt(argc, argv, "hi:o:")) != -1)
{
    ...as before...
}

This effectively consumes the first option and then rejigs things to the orthodox format. This works with any version of getopt() that is remotely compliant with the standards (de facto and de jure). Note that if you don't reassign argv[1] = argv[0];, getopt() will use the value in the original argv[1] (the number in this example) as the 'name of the program'.

Using GNU getopt()

With GNU getopt(), there are two ways to handle the problem. One uses the 'return in order' feature so that non-option ('file name') arguments are treated as if they were prefixed by an option character code 1 (ASCII SOH control character; aka Control-A). The other uses the default mode whereby getopt() permutes the options as it processes them. Note that this is not available by default on Mac OS X, amongst other platforms.

This code almost does both jobs; you simply have to change the option string between the 'permute' mode (shown) and the 'return in order' mode using "-hi:o:".

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

int main(int argc, char **argv)
{
    int n;
    int opt;
    char *ifile = 0;
    char *ofile = 0;

    n = atoi(argv[1]);

    while ((opt = getopt(argc, argv, "hi:o:")) != -1)
    {
        printf("Option: %c\n", opt);
        switch (opt)
        {
        case 'i':
            ifile = optarg;
            break;
        case 'o':
            ofile = optarg;
            break;
        case 'h':
            printf("...");
            break;
        case 1:
            n = atoi(optarg);
            break;
        default:
            printf("Invalid Option %d\n", opt);
            exit(1);
        }
    }

    printf("argc = %d; optind = %d\n", argc, optind);
    for (int i = optind; i < argc; i++)
        printf("argv[%d] = %s\n", i, argv[i]);

    if (ifile != 0)
        printf("i-file: %s\n", ifile);
    if (ofile != 0)
        printf("o-file: %s\n", ofile);
    printf("%d\n", n);

    return 0;
}

Example run with 'permute':

$ go9 9 -i in -o out
Option: i
Option: o
argc = 6; optind = 5
argv[5] = 9
i-file: in
o-file: out
9
$

Example run with 'return in order':

$ go9 9 -i in -o out
Option: 
Option: i
Option: o
argc = 6; optind = 6
i-file: in
o-file: out
9
$

Make sure you do not have environment variable POSIXLY_CORRECT set if you want this to work. You can prefix the option string with a + to force POSIX-like behaviour.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top