【问题标题】:array subscript has type 'char'数组下标的类型为 'char'
【发布时间】:2012-04-17 06:28:38
【问题描述】:

我有以下代码从命令行读取参数。如果字符串是 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'

【问题讨论】:

    标签: c compiler-warnings ctype


    【解决方案1】:

    问题在于isdigit() 宏接受一个整数参数,该整数要么是 EOF 值,要么是 unsigned char 的值。

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

    在所有情况下,参数都是int,其值应为 可表示为 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 等)。通过使用*args[1] - '0' 作为exit() 的参数,你会得到2(无引号)。您不需要对该表达式进行强制转换,尽管它不会造成太大的伤害。

    【讨论】:

    • 太棒了,它处理了“数组下标的类型为'char'”警告,但我仍然得到隐式的退出声明。我的标题中已经有#include
    • 如果exit() 未在<stdlib.h> 中声明,则正在使用的<stdlib.h> 标头已损坏。你确定你没有一个名为<stdlib.h> 的空文件潜伏在意想不到的地方吗?使用gcc -H 准确查看包含哪些标题。
    【解决方案2】:

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

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

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

    第二个警告表示您想使用退出函数,但尚未定义。这意味着您必须执行所需的#include。

    #include <stdlib.h> 
    

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

    顺便说一句,如果这段代码在你的“main”函数中,你不能检查“arg[1] == NULL”,如果用户没有在命令中提供任何参数,这可能会导致分段错误-线。您必须检查 argc 值(int 参数)是否大于 1。

    【讨论】:

    • 强制转换为int 会删除警告但不会删除危险;只有将其转换为 unsigned char 然后将其提升为 int 才是正确的。
    【解决方案3】:

    目前还不清楚什么你想作为退出代码给出,但可能你想要args[1][0] - '0'作为字符表示的十进制值而不是字符的代码。

    如果你这样做,你会得到那个表达式的类型是 int 的副作用,你不会看到警告。

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

    【讨论】:

    • 我实际上是在尝试使用角色的实际代码,所以如果有人在输入中键入 exit 1,那么我想在我的代码中给出命令 exit(1)。
    • 在这种情况下,您需要按照 Jens 的建议和我的建议减去 '0'(注意引号!)。
    【解决方案4】:

    尝试改变

    isdigit(*args[1])
    

    isdigit(args[1][0])
    

    您的其他错误是因为您没有使用定义exit 函数的#include &lt;stdlib.&gt;

    【讨论】:

    • 但是如果args[1]char*,那么*args[1] 不应该是char吗?
    • @cmh 我试过了,但仍然收到警告。我确实在标题中有 stdlib.h。
    • @user994165 尝试使用gcc -std=c99,如here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-07
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多