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

Ras*_*yak 39 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();
}
Run Code Online (Sandbox Code Playgroud)

Pav*_*ath 71

简单,改变

char j;
Run Code Online (Sandbox Code Playgroud)

unsigned char j;
Run Code Online (Sandbox Code Playgroud)

或者只是一个平原 (u)int

unsigned int j;
int j;
Run Code Online (Sandbox Code Playgroud)

来自GCC警告

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

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

  • 使用类型为`int`的数组索引不**导致任何警告,虽然它也允许负索引... @Pavan Manjunath (8认同)

Rol*_*lig 8

这是一个典型的案例,海湾合作委员会在其诊断中使用了过于官僚和间接的措辞,这使得很难理解这个有用警告背后的真正问题。

// Bad code example
int demo(char ch, int *data) {
    return data[ch];
}
Run Code Online (Sandbox Code Playgroud)

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

  • char 可以容纳一个“来自基本执行字符集的字符”(其中至少包括 AZ、az、0-9 和几个标点字符)。
  • unsigned char 可以保存至少 0 到 255 范围内的值。
  • signed char 可以保存至少 -127 到 127 范围内的值。

C 标准定义该类型的char行为方式与signed charor 或相同unsigned char。实际选择这些类型中的哪一种取决于编译器和操作系统,并且必须由它们记录。

arr[index]表达式访问数组元素时,GCC 调用indexa 下标。在大多数情况下,这个数组索引是一个无符号整数。这是常见的编程风格,如果数组索引为负数,Java 或 Go 等语言会抛出异常。

在 C 中,越界数组索引被简单地定义为调用未定义的行为。编译器不能在所有情况下都拒绝负数组索引,因为以下代码完全有效:

const char *hello = "hello, world";
const char *world = hello + 7;
char comma = world[-2];   // negative array index
Run Code Online (Sandbox Code Playgroud)

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

isspace(' ');
isspace('!');
isspace('ä');
Run Code Online (Sandbox Code Playgroud)

前两种情况是可以的,因为空格和感叹号来自基本执行字符集,因此被定义为表示相同,无论编译器定义char为有符号还是无符号。

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

unsigned char auml_unsigned = 'ä';   // == 228
signed   char auml_signed   = 'ä';   // == -28
Run Code Online (Sandbox Code Playgroud)

现在想象该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];
}
Run Code Online (Sandbox Code Playgroud)

这种实现技术是典型的。

回到调用isspace('ä'),假设编译器已定义charsigned char并且编码为 ISO 8859-1。调用该函数时,字符的值为 -28,并将该值转换为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]);
}
Run Code Online (Sandbox Code Playgroud)

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

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

上面的示例将字符值-28直接转换为intvalue -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
}
Run Code Online (Sandbox Code Playgroud)

本示例将字符值-28直接转换为unsigned int. 假设使用通常的二进制补码整数表示的 32 位平台,-28通过重复添加 2^32 来转换该值,直到该值在 范围内unsigned int。在这种情况下,这会导致数组索引 4_294_967_268,它太大了。

  • “_类型 `char` 等效于 `signed char` 或 `unsigned char`_”:`char` 必须与 `signed char` 或 `unsigned char` 表现相同,并且具有相同的表示形式,但是 `char` 、 `signed char` 和 `unsigned char` 是 C 中的三种不同类型。“_负数组索引被简单地定义为调用未定义的行为。_”:带有负值的数组索引在 C 中是完美定义的,因为 `arr[n ]` 等价于 `*(arr + n)`。这种_可能_导致未定义行为的一种方式是指针算术是否导致越界访问。 (2认同)
  • [报告为 GCC bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94182) (2认同)