name name - 2 months ago 15
C Question

Multiple integer arguments with getopt?

What is the best way to handle multiple integer arguments while using getopt? I have to be able to enter something like this on the command line:

calc -a 100 50
and it will add up 100 and 50.

while ((opt = getopt(argc, argv, "adms")) != -1)
{

value = atoi(argv[optind + 1]);
printf("value : %d\n", value);

switch (opt)
{
case 'a': aFlag = 1; num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
break;
case 'd': dFlag = 1;
break;
case 'm': break;
case 's': break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}

if (aFlag == 1)
{
num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
}
if (dFlag == 1)
{
num2 = atoi(argv[optind]);
sub = num2 / value;
printf("%d / %d = %d\n" , num2, value, sum);
}

Answer

I think that the interface you're after is probably:

./program -a 100 50

which accepts a single option -a (alternatives -m, -s and -d), and then processes the other arguments as a list of numbers, rather than as values attached to the option. This works fine unless you planned to be able to use:

./program -a 100 50 -m 20 30

to do addition and multiplication.

What do you want to do if someone can't make their mind up and tries:

./program -am 100 50

Should it be an error, or should -a or -m win? You can argue for any of those with some degree of coherency. I'd go with an error, though.

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

static int op_add(int a, int b) { return a + b; }
static int op_sub(int a, int b) { return a - b; }
static int op_mul(int a, int b) { return a * b; }
static int op_div(int a, int b) { return a / b; }

int main(int argc, char **argv)
{
    int (*fun)(int, int) = 0;
    char op;
    int opt;

    while ((opt = getopt(argc, argv, "adms")) != -1)
    {
        if (fun != 0)
        {
            fprintf(stderr, "%s: you can't use two operations\n", argv[0]);
            return 1;
        }
        switch (opt)
        {
        case 'a': fun = op_add; op = '+'; break;
        case 'd': fun = op_div; op = '/'; break;
        case 'm': fun = op_mul; op = '*'; break;
        case 's': fun = op_sub; op = '-'; break;
        default:
            fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
            return 1;
        }
    }
    if (fun == 0 || optind + 2 != argc)
    {
        fprintf(stderr, "Usage: %s [-adms] num1 num2\n", argv[0]);
        return 1;
    }

    int res = fun(atoi(argv[optind]), atoi(argv[optind+1]));
    printf("%s %c %s = %d\n", argv[optind], op, argv[optind+1], res);
    return 0;
}

The error checking on the values in the 'numeric' arguments is reprehensibly sloppy (meaning, non-existent). There's no division by zero check, either. But that at least produces plausible answers. It would probably be better to have an array of structures saving the function pointer and the operation character, but that sort of refinement is for you to deal with.

If you need a negative number, use -- to mark the end of the options:

$ ./program -m -- -39 -75
-39 * -75 = 2925
$

Just in case you're not sure about it, int (*fun)(int, int) is a pointer to a function that takes two int arguments and returns an int result. It allows the code to select which function to execute at runtime.

Comments