Question

I have the following code to read an argument from the command line. If the string is 1 character long and a digit I want to use that as the exit value. The compiler gives me a warning on the second line (array subscript has type 'char' ) This error comes from the second part after the "&&" .

    if (args[1] != NULL) {
        if ((strlen(args[1]) == 1) && isdigit(*args[1]))
            exit(((int) args[1][0]));
        else
            exit(0);
    }
}

Also, when I use a different compiler I get two errors on the next line (exit).

builtin.c: In function 'builtin_command':
builtin.c:55: warning: implicit declaration of function 'exit'
builtin.c:55: warning: incompatible implicit declaration of built-in function 'exit'
Was it helpful?

Solution

The trouble is that the isdigit() macro takes an argument which is an integer that is either the value EOF or the value of an unsigned char.

ISO/IEC 9899:1999 (C Standard – old), §7.4 Character handling <ctype.h>, ¶1:

In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.

On your platform, char is signed, so if you have a character in the range 0x80..0xFF, it will be treated as a negative integer. The usual implementation of the isdigit() macros is to use the argument to index into an array of flag bits. Therefore, if you pass a char from the range 0x80..0xFF, you will be indexing before the start of the array, leading to undefined behaviour.

#define isdigit(x)  (_CharType[(x)+1]&_Digit)

You can safely use isdigit() in either of two ways:

int c = getchar();

if (isdigit(c))
    ...

or:

if (isdigit((unsigned char)*args[1]))
    ...

In the latter case, you know that the value won't be EOF. Note that this is not OK:

int c = *args[1];

if (isdigit(c))  // Undefined behaviour if *args[1] in range 0x80..0xFF
    ...

The warning about 'implicit definition of function exit' means you did not include <stdlib.h> but you should have done so.

You might also notice that if the user gives you a 2 as the first character of the first argument, the exit status will be 50, not 2, because '2' is (normally, in ASCII and UTF-8 and 8859-1, etc) character code 50 ('0' is 48, etc). You'd get 2 (no quotes) by using *args[1] - '0' as the argument to exit(). You don't need a cast on that expression, though it won't do much harm.

OTHER TIPS

It seems that the compiler you use has a macro for isdigit (and not a function, you wouldn't have a warning if it was the case) that uses the argument as a subscript for an array. That's why isdigit takes an INT as argument, not a char.

One way to remove the warning it to cast your char to int :

isdigit(*args[1]) => isdigit((int)(*args[1]))

The second warning means you want to use the exit function, but it has not been defined yet. Which means you have to do the required #include.

#include <stdlib.h> 

is the standard in c-library to use exit(int) function.

BTW, if this code is in your "main" function, you mustn't check "arg[1] == NULL", which could lead to a segmentation fault if the user didn't provide any argument on the command-line. You must check that the argc value (the int parameter) is greater than 1.

It is not completely clear what you want to give as exit code, but probably you want args[1][0] - '0' for the decimal value that the character represents and not the code of the character.

If you do it like that, you'd have the side effect that the type of that expression is int and you wouldn't see the warning.

For exit you probably forgot to include the header file.

Try changing

isdigit(*args[1])

to

isdigit(args[1][0])

Your other errors are because you aren't using #include <stdlib.> which defines the exit function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top