学习C艰难之路练习14错误(警告:数组下标有类型?char?[-Wchar-subscripts]

时间:2015-01-28 15:08:27

标签: c

我正在按照该教程进行操作,我使用cygwin编译器运行WindowsXP 32位,该教程要求我运行此代码:

#include <stdio.h>
#include <ctype.h>

// forward declarations
int can_print_it(char ch);
void print_letters(char arg[]);

void print_arguments(int argc, char *argv[])
{
    int i = 0;

    for(i = 0; i < argc; i++) {
        print_letters(argv[i]);
    }
}

void print_letters(char arg[])
{
    int i = 0;

    for(i = 0; arg[i] != '\0'; i++) {
        char ch = arg[i];

        if(can_print_it(ch)) {
            printf("'%c' == %d ", ch, ch);
        }
    }

    printf("\n");
}

int can_print_it(char ch)
{
    return isalpha(ch) || isblank(ch);
}


int main(int argc, char *argv[])
{
    print_arguments(argc, argv);
    return 0;
}

但我一直在遇到这个警告:

$ make ex14
cc -Wall -g    ex14.c   -o ex14
ex14.c: In function ?can_print_it?:
ex14.c:34:5: warning: array subscript has type ?char? [-Wchar-subscripts]
    return isalpha(ch) || isblank(ch);
    ^
ex14.c:34:5: warning: array subscript has type ?char? [-Wchar-subscripts]

我试过四处搜索,虽然我发现很多线程都在谈论类似的错误,他们的答案/解决方案都没有在我的代码上工作,但我找不到与学习C相关的问题艰难的方式 exercise 14

那么我应该怎样做才能摆脱这种警告?

4 个答案:

答案 0 :(得分:4)

警告的原因是char值通常是正值,但有时它们可​​能是负值;对于程序员来说这可能是意料之外的(特别是因为在某些实现中char总是正数),并且对数组使用负索引显然是一件坏事。

isalpha完全支持你的背后。您可以通过将char转换为int或通过将其存储在int中来修复警告 - 但这并不能解决问题,因为负char将被强制转换为具有完全相同问题的负int。您可以通过将char转换为unsigned char来修复警告和问题。

答案 1 :(得分:3)

所以,如果我们看一下gcc document for warnings which covers -Wchar-subscripts,那就说:

  

如果数组下标的类型为char,则发出警告。这是导致错误的常见原因,因为程序员经常忘记这种类型是在某些机器上签名的。 -Wall启用此警告。

实现定义 char 是签名还是未签名,如果使用 unsigned char ,则警告将消失。

我们可以从草案C99标准中看到,<ctype.h>中函数的参数可以表示为 unsigned char EOF,来自{{1}部分} 字符处理&lt; ctype.h&gt;

  

在所有情况下,参数都是一个int,其值应为   可表示为无符号字符或等于宏EOF的值。如果   参数有任何其他值,行为未定义

所以最有可能将7.4isalpha实现为使用查找表的宏,因此这段代码确实会使用char来索引数组。

答案 2 :(得分:0)

isalphaisblank的输入类型应为int,而不是char。这是核心问题。其余的是如何实施的细节。如果使用-E标志来预处理代码,则函数can_print_it会扩展为:

int can_print_it(char ch)
{
    return (((__ctype_ptr__+sizeof(""[ch]))[(int)(ch)])&(01|02)) || __extension__ ({ __typeof__ (ch) __x = (ch); (((__ctype_ptr__+sizeof(""[__x]))[(int)(__x)])&0200) || (int) (__x) == '\t';});
}

如您所见,输入chisalpha的实现中用作数组索引。临时__xch的类型相同,在isblank的实现中用作数组索引。

您可以通过以下方式修正警告:

  1. can_print_it的参数类型更改为int

    int can_print_it(int ch)
    {
        return isalpha(ch) || isblank(ch);
    }
    
  2. 在函数中创建临时变量并使用它来调用isalphaisblank

    int can_print_it(char ch)
    {
        int temp = ch;
        return isalpha(temp) || isblank(temp);
    }
    

答案 3 :(得分:0)

您的编译器似乎已旧或已损坏。 GCC 4.9.1编译此代码时没有警告/错误,给出:

gcc test.c -std=c11 -pedantic-errors -Wall -Wextra

编译器必须隐式地将您的char提升为isalpha等函数所需的int。无论char的实现定义签名如何,它都会进行此促销。 char的大小也无关紧要,因为char总是一个小整数类型。

我期望编译器从这段代码中给出的唯一警告类似于“从char到int的隐式转换”。