数组下标有'char'类型

use*_*165 3 c ctype compiler-warnings

我有以下代码从命令行读取参数.如果字符串长度为1个字符,并且我想将其用作退出值.编译器在第二行给出了警告(数组下标的类型为'char')此错误来自"&&"之后的第二部分.

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

此外,当我使用不同的编译器时,我在下一行(退出)上得到两个错误.

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'
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 8

麻烦的是isdigit()宏接受一个参数,该参数是一个整数,它是值EOF或一个值unsigned char.

ISO/IEC 9899:1999(C标准 - 旧),§7.4字符处理<ctype.h>,1:

在所有情况下,参数都是a int,其值应表示为unsigned char或等于宏EOF的值.如果参数具有任何其他值,则行为未定义.

在您的平台上,char已签名,因此如果您的字符在0x80..0xFF范围内,则将其视为负整数.isdigit()宏的通常实现是使用参数来索引标志位数组.因此,如果char从0x80..0xFF范围传递a ,则将在数组开始之前进行索引,从而导致未定义的行为.

#define isdigit(x)  (_CharType[(x)+1]&_Digit)
Run Code Online (Sandbox Code Playgroud)

您可以安全地使用isdigit()以下两种方式之一:

int c = getchar();

if (isdigit(c))
    ...
Run Code Online (Sandbox Code Playgroud)

要么:

if (isdigit((unsigned char)*args[1]))
    ...
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,您知道该值不是EOF.请注意,这不行:

int c = *args[1];

if (isdigit(c))  // Undefined behaviour if *args[1] in range 0x80..0xFF
    ...
Run Code Online (Sandbox Code Playgroud)

关于"函数退出的隐式定义"的警告意味着你没有包含,<stdlib.h>但你应该这样做.

你可能还会注意到,如果用户给你一个2作为第一个参数的第一个字符,退出状态将是50而不是2,因为'2'(通常是ASCII和UTF-8和8859-1等)字符代码50('0'48等).2通过使用*args[1] - '0'作为参数,你得到(没有引号)exit().你不需要对该表达式进行强制转换,但它不会造成太大伤害.