警告:数组下标的类型为char

时间:2012-04-02 07:25:23

标签: c codeblocks

当我运行这个程序时,我收到警告“数组下标有'char'类型”。 请帮帮我哪里出错了。我正在使用code :: blocks IDE

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
void NoFive()
{
    long long int cal;
    char alpha[25];
    char given[100] = "the quick brown fox jumped over the cow";
    int num[25];
    int i, k;
    char j;
    j = 'a';
    k = 26;
    cal = 1;
    for(i = 0; i <= 25; i++)
    {
        alpha[i] = j++;
        num[i] = k--;
      //  printf("%c = %d \n", alpha[i], num[i]);
    }
    for(i = 0; i <= (strlen(given) - 1); i++)
    {
        for(j = 0; j <= 25; j++)
        {
         if(given[i] == alpha[j]) ***//Warning array subscript has type char***
         {
            cal = cal * num [j]; ***//Warning array subscript has type char***
         }
         else
         {

         }
        }
    }
printf(" The value of cal is %I64u ", cal);
}

main()
{
NoFive();
}

3 个答案:

答案 0 :(得分:63)

简单,改变

char j;

unsigned char j;

或只是普通(u)int

unsigned int j;
int j;

来自GCC Warnings

  

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

编译器不希望您无意中指定负数组索引。因此警告!

答案 1 :(得分:6)

这是GCC在诊断中使用过分官僚和间接措词的典型情况,这使得很难理解此有用警告背后的真正问题。

// Bad code example
int demo(char ch, int *data) {
    return data[ch];
}

根本问题是C编程语言为“字符”定义了几种数据类型:

  • char可以包含“基本执行字符集中的字符”(至少包括A-Z,a-z,0-9和几个标点符号)。
  • unsigned char可以保存至少0到255之间的值。
  • signed char至少可以保存-127到127范围内的值。

C标准定义类型char的行为与signed charunsigned char相同。实际选择哪种类型取决于编译器和操作系统,并且必须由它们进行记录。

arr[index]表达式访问数组的元素时,GCC将index称为下标。在大多数情况下,此数组索引是无符号整数。这是常见的编程风格,如果数组索引为负,则Java或Go之类的语言都会引发异常。

在C语言中,越界数组索引仅定义为调用未定义行为。由于以下代码完全有效,因此编译器不能在所有情况下都拒绝负数组索引:

const char *hello = "hello, world";
const char *world = hello + 7;
char comma = world[-2];   // negative array index

C标准库中有一个地方很难正确使用,那就是头文件<ctype.h>中的字符分类函数,例如isspace。表达式isspace(ch)看起来好像将一个字符作为其参数:

isspace(' ');
isspace('!');
isspace('ä');

前两种情况都可以,因为空格和感叹号来自基本执行字符集,因此无论编译器是否定义{{1} }签名或未签名。

但是最后一种情况,变音符号char是不同的。它通常位于基本执行字符集之外。在1990年代流行的字符编码ISO 8859-1中,字符'ä'表示如下:

'ä'

现在想象一下unsigned char auml_unsigned = 'ä'; // == 228 signed char auml_signed = 'ä'; // == -28 函数是使用数组实现的:

isspace

这种实现技术很典型。

回到调用static const int isspace_table[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, // and so on }; int isspace(int ch) { return isspace_table[ch]; } ,假设编译器已将isspace('ä')定义为char,并且编码为ISO 8859-1。调用该函数时,字符的值为-28,并且将此值转换为signed char,并保留该值。

这将导致表达式int,该表达式将访问数组范围之外的表。这会引起未定义的行为。

编译器警告正是描述了这种情况。

isspace_table[-28]头调用函数的正确方法是:

<ctype.h>

还有几种看起来很相似但错误的方法。

// Correct example: reading bytes from a file
int ch;
while ((ch = getchar()) != EOF) {
    isspace(ch);
}

// Correct example: checking the bytes of a string
const char *str = "hello, Ümläute";
for (size_t i = 0; str[i] != '\0'; i++) {
    isspace((unsigned char) str[i]);
}

以上示例将字符值// WRONG example: checking the bytes of a string for (size_t i = 0; str[i] != '\0'; i++) { isspace(str[i]); // WRONG: the cast to unsigned char is missing } // WRONG example: checking the bytes of a string for (size_t i = 0; str[i] != '\0'; i++) { isspace((int) str[i]); // WRONG: the cast must be to unsigned char } 直接转换为-28int,从而导致数组索引为负。

-28

此示例将字符值// WRONG example: checking the bytes of a string for (size_t i = 0; str[i] != '\0'; i++) { isspace((unsigned int) str[i]); // WRONG: the cast must be to unsigned char } 直接转换为-28。假定一个具有通常的二进制补码整数表示的32位平台,则通过重复加2 ^ 32直到值在unsigned int范围内,来转换值-28。在这种情况下,这将导致数组索引4_294_967_268太大。

答案 2 :(得分:0)

请注意,Roland Illig 的解释有些不完整;这些天,'ä' 甚至可能无法编译(或者它可能编译为不适合一个字节的东西,但这非常依赖于实现,甚至可能是 UB)。 如果您使用的是 UTF-8,则 "ä""\xc3\xa4" 相同。