简体   繁体   中英

C: getopt(): option does not seem to have effect

I am trying out the following C code (saved in file called testgetopt.c):

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

void usage(char *s)
{
    fprintf(stderr, "Usage: %s [-d] -i input-TIFF-file -o output-raw-file\n", s);
    fprintf(stderr, "Note: -d indicates debugging option\n");
}

int main(int argc, char **argv) { 
    char c;
    size_t i;
    char *itext = NULL, *otext = NULL;
    FILE *fout;
    short debug = 0;

    if ((c = getopt(argc, argv, "di:o:")) == EOF) {
        usage(argv[0]);
        exit(1);
    }

    while ((c = getopt(argc, argv, "di:o:")) != EOF) {
        switch (c) {
        case 'd':
            debug = 1;
            break;
        case 'i':
            itext = optarg;
            break;
        case 'o':
            otext = optarg;
            break;
        case '?':
            if (optopt == 'i' || optopt == 'o')
                fprintf (stderr, "Option -%c requires an argument.\n", optopt);
            else if (isprint (optopt))
                fprintf (stderr, "Unknown option `-%c'.\n", optopt);
            else
                fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
            usage(argv[0]);
            exit(1);
        default:
            fprintf(stderr, "Both -i and -o are needed\n");
            usage(argv[0]);
            exit(1);
        }
    }
    printf("debug = %i\n", debug);
    if (debug) 
        printf ("input file = %s, output file = %s\n", itext, otext);
    return EXIT_SUCCESS;
}

I compile using:

gcc testgetopt.c 

But regardless of whether I include -d or not, I always get debug set at 0. The program should have -d set debug at 1, 0 otherwise.

What is being done wrong?

Here are the examples:

Let us first try with no -d

./a.out -i in.dat -o out.dat
debug = 0

Let us next try with -d included.

./a.out -d -i in.dat -o out.dat
debug = 0

Thank you in advance for any help and suggestions!

The problem is that you are calling getopt as a sanity check and then not using its result when it succeeds. That means the first option is always discarded. You can easily verify this by putting -d as a non-first option:

$ ./a.out -i in.dat -o out.dat -d
debug = 1
input file = (null), output file = out.dat

You can see that the -d did take effect this time but the first argument, -i , is not set.

There are several ways to fix this. The recommended way (IMHO) is to remove the first getopt call. Then change the sanity check to verify the actual options. That is, there should be code after the getopt loop which verifies that all mandatory options have been provided.

For example:

int main(int argc, char **argv) { 
    char c;
    size_t i;
    char *itext = NULL, *otext = NULL;
    FILE *fout;
    short debug = 0;

    /* REMOVED THIS BLOCK OF CODE
    if ((c = getopt(argc, argv, "di:o:")) == EOF) {
        usage(argv[0]);
        exit(1);
    }
    */

    while ((c = getopt(argc, argv, "di:o:")) != EOF) {
        switch (c) {
        case 'd':
            debug = 1;
            break;
        case 'i':
            itext = optarg;
            break;
        case 'o':
            otext = optarg;
            break;
        case '?':
            if (optopt == 'i' || optopt == 'o')
                fprintf (stderr, "Option -%c requires an argument.\n", optopt);
            else if (isprint (optopt))
                fprintf (stderr, "Unknown option `-%c'.\n", optopt);
            else
                fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
            usage(argv[0]);
            exit(1);
        default:
            fprintf(stderr, "Both -i and -o are needed\n");
            usage(argv[0]);
            exit(1);
        }
    }

    /* ADD SOME ARGUMENT SANITY CHECKS */
    if (!itext || !otext) {
        printf("Missing mandatory arguments\n");
        exit(1);
    }

    printf("debug = %i\n", debug);
    if (debug) 
        printf ("input file = %s, output file = %s\n", itext, otext);
    return EXIT_SUCCESS;
}

Because you are calling getopt twice, you need to reset optind = 1; between the calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM