数组下标有'char'类型

时间:2012-04-17 06:28:38

标签: c compiler-warnings ctype

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

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

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

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'

4 个答案:

答案 0 :(得分:8)

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

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

  

在所有情况下,参数都是int,其值应为。{1}}   可表示为unsigned char或等于宏EOF的值。如果   参数有任何其他值,行为未定义。

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

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

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

int c = getchar();

if (isdigit(c))
    ...

或:

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

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

int c = *args[1];

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

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

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

答案 1 :(得分:1)

您使用的编译器似乎有一个用于isdigit的宏(而不是一个函数,如果是这样的话就不会有警告),它使用该参数作为数组的下标。 这就是为什么isdigit将INT作为参数而不是char。

删除警告它将char转换为int的一种方法:

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

第二个警告意味着您要使用退出功能,但尚未定义。这意味着您必须执行所需的#include。

#include <stdlib.h> 

是c-library中使用exit(int)函数的标准。

BTW,如果此代码在“main”函数中,则不能检查“arg [1] == NULL”,如果用户未在命令上提供任何参数,则可能导致分段错误-线。您必须检查argc值(int参数)是否大于1.

答案 2 :(得分:0)

你想要作为退出代码提供什么并不完全清楚,但是你可能希望args[1][0] - '0'代表字符所代表的十进制值,而不是字符代码。< / p>

如果您这样做,您会产生副作用,即该表达式的类型为int,您将看不到警告。

对于exit,您可能忘记包含头文件。

答案 3 :(得分:-1)

尝试更改

isdigit(*args[1])

isdigit(args[1][0])

您的其他错误是因为您没有使用定义#include <stdlib.>功能的exit