Advertencia: el subíndice de matriz tiene tipo char

9 minutos de lectura

Cuando estoy ejecutando este programa, recibo la advertencia “el subíndice de matriz tiene el tipo ‘char'”. Por favor, ayúdame, ¿dónde está yendo mal? Estoy usando código::bloquea 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();
}

  • gcc.gnu.org/onlinedocs/gcc/Warning-Options.html Arrojará algo de luz sobre por qué esto es una advertencia.

    – ta.speot.es

    2 de abril de 2012 a las 7:27

  • for(i = 0; i <= 25; i++) también está mal (dos veces). Debiera ser for(i = 0; i < 25; i++) {...} La matriz tiene 25 elementos. Y for(i = 0; i <= (strlen(given) - 1); i++) es debatible.

    – salvaje

    26 de abril de 2012 a las 18:15

  • @ta.speot.is lamentablemente la documentación de GCC no arroja ninguna luz en el por qué. Ni siquiera trata de explicar la situación.

    – Roland Illig

    15 de marzo de 2020 a las 18:43

  • @RolandIllig dice Advertir si un subíndice de matriz tiene tipo char. Esta es una causa común de error, ya que los programadores a menudo olvidan que este tipo está firmado en algunas máquinas. Esta advertencia está habilitada por -Wall. ¿Por qué querrías un subíndice negativo?

    – ta.speot.es

    16 de marzo de 2020 a las 1:00

  • @ta.speot.is Yo no querer un subíndice negativo, lo obtengo implícitamente sin hacer nada al respecto. Ese es el problema.

    – Roland Illig

    16 de marzo de 2020 a las 3:25

avatar de usuario
Pavan Manjunath

sencillo, cambio

char j;

para

unsigned char j;

o a un simple (u)int

unsigned int j;
int j;

Desde Advertencias de GCC

-Wchar-subíndices Advertir si un subíndice de matriz tiene tipo char. Esta es una causa común de error, ya que los programadores a menudo olvidan que este tipo está firmado en algunas máquinas. Esta advertencia está habilitada por -Wall.

El compilador no quiere que especifique inadvertidamente un índice de matriz negativo. ¡Y de ahí la advertencia!

  • Usando un índice de matriz de tipo int lo hace no daría lugar a alguna advertencia, aunque también permitiría índices negativos… @Pavan Manjunath

    – alk

    26 de abril de 2012 a las 17:04


  • @alk Ah. Fue un error tipográfico. me refería unsigned char que solo unsigned. De todos modos, solo estaba señalando los índices negativos. Sin embargo, edité mi publicación para que sea clara para futuros visitantes 🙂

    – Pavan Manjunath

    26 de abril de 2012 a las 18:03


  • @alk: Un par de diferencias entre int y char: (1) No hay compiladores (al menos ninguno que no se considere ni remotamente “normal”) donde int podría esperarse razonablemente que no esté firmado; (2) Código que usa tipo char como un subíndice de matriz es más probable que el código que usa tipo int, para suponer que todos los caracteres literales, o todos los caracteres de los literales de cadena, representan valores positivos. No estoy seguro de si todos los caracteres del “conjunto de caracteres C” deben ser positivos, pero sé que los caracteres fuera de ese conjunto no lo son.

    – Super gato

    26 de abril de 2012 a las 18:14

  • Recibí esta advertencia con el siguiente código: context->ptr[0] = (char)superior(c); donde “ptr” es de tipo “char *”. ¿Está pensando el compilador que 0 es un carácter firmado y, por lo tanto, podría ser negativo?

    – AlastairG

    30 de noviembre de 2013 a las 14:43


  • Simplemente cambiando el tipo de char para int o unsigned int Está Mal. Lea cualquier buen manual sobre el <ctype.h> función para aprender los detalles.

    – Roland Illig

    7 febrero 2021 a las 21:44

avatar de usuario
roland illig

Este es un caso típico en el que GCC utiliza una redacción excesivamente burocrática e indirecta en sus diagnósticos, lo que dificulta la comprensión del problema real detrás de esta útil advertencia.

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

El problema de raíz es que el lenguaje de programación C define varios tipos de datos para “caracteres”:

  • char puede contener un “carácter del conjunto de caracteres de ejecución básica” (que incluye al menos AZ, az, 0-9 y varios caracteres de puntuación).
  • unsigned char puede contener valores de al menos el rango de 0 a 255.
  • signed char puede contener valores de al menos el rango -127 a 127.

El estándar C define que el tipo char se comporta de la misma manera que signed char o unsigned char. Cuál de estos tipos se elige realmente depende del compilador y del sistema operativo y debe ser documentado por ellos.

Cuando un elemento de una matriz es accedido por el arr[index] expresión, GCC llama a la index un subíndice. En la mayoría de las situaciones, este índice de matriz es un entero sin signo. Este es un estilo de programación común y los lenguajes como Java o Go lanzan una excepción si el índice de la matriz es negativo.

En C, los índices de matriz fuera de los límites se definen simplemente como invocando un comportamiento indefinido. El compilador no puede rechazar índices de matrices negativos en todos los casos, ya que el siguiente código es perfectamente válido:

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

Hay un lugar en la biblioteca estándar de C que es difícil de usar correctamente, y son las funciones de clasificación de caracteres del encabezado. <ctype.h>tal como isspace. La expresion isspace(ch) parece que tomaría un carácter como argumento:

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

Los primeros dos casos están bien ya que el espacio y el signo de exclamación provienen del conjunto de caracteres de ejecución básica y, por lo tanto, están definidos para ser representados de la misma manera, sin importar si el compilador define char como firmado o como sin firmar.

Pero el último caso, la diéresis 'ä', es diferente. Por lo general, se encuentra fuera del juego de caracteres de ejecución básico. En la codificación de caracteres ISO 8859-1, que fue popular en la década de 1990, el carácter 'ä' se representa así:

unsigned char auml_unsigned = 'ä';   // == 228
signed   char auml_signed   = 'ä';   // == -28

Ahora imagina que el isspace La función se implementa usando una matriz:

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];
}

Esta técnica de implementación es típica.

Volviendo a la llamada isspace('ä')asumiendo que el compilador ha definido char ser signed char y que la codificación es ISO 8859-1. Cuando se llama a la función, el valor del carácter es -28 y este valor se convierte en un intpreservando el valor.

Esto da como resultado la expresión isspace_table[-28], que accede a la tabla fuera de los límites de la matriz. Esta invoca un comportamiento indefinido.

Es exactamente este escenario el que describe la advertencia del compilador.

La forma correcta de llamar a las funciones desde el <ctype.h> el encabezado es:

// 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]);
}

También hay varias formas que se ven muy similares pero están equivocadas.

// 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
}

Los ejemplos anteriores convierten el valor del carácter -28 directamente a la int valor -28lo que conduce a un índice de matriz negativo.

// 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
}

Este ejemplo convierte el valor del carácter -28 directamente a unsigned int. Suponiendo una plataforma de 32 bits con la representación habitual de enteros en complemento a dos, el valor -28 se convierte sumando repetidamente 2^32 hasta que el valor esté en el rango de unsigned int. En este caso, esto da como resultado el índice de matriz 4_294_967_268, que es demasiado grande.

  • el tipo char es equivalente a cualquiera signed char o para unsigned char“: char debe comportarse y tener la misma representación que signed char o unsigned charpero char, signed chary unsigned char hay tres tipos distintos en C. “los índices de matriz negativos se definen simplemente como invocando un comportamiento indefinido.“: la indexación de matrices con valores negativos está perfectamente definida en C, ya que arr[n] es equivalente a *(arr + n). De una manera esto lata conducir a un comportamiento indefinido es si la aritmética de punteros conduce a un acceso fuera de los límites.

    – ad absurdum

    15 de marzo de 2020 a las 19:04

  • Reportado como un error de GCC

    – Roland Illig

    17 mayo 2020 a las 19:57

  • Creo que cambiar ciegamente los parámetros a unsigned char podría introducir regresiones si el código restante se basa en la función ctype respectiva para verificar EOF. Al menos en algunos casos hipotéticos, dependiendo del valor resultante de la conversión, EOF podría ser considerado erróneamente como miembro de una de las clases por las funciones ctype. Está evitando elegantemente esta posibilidad en sus ejemplos, pero creo que es un posible escollo que vale la pena mencionar. Además, mencionar implementaciones macro de las funciones ctype dejaría en claro por qué el compilador realmente advierte con esta advertencia específica (?)

    – stefanct

    22 de noviembre de 2021 a las 14:39

Tenga en cuenta que la explicación de Roland Illig está ligeramente incompleta; estos días, 'ä' podría ni siquiera compilar (o podría compilarse en algo que no cabe en un byte, pero eso depende mucho de la implementación o posiblemente incluso UB). Si está utilizando UTF-8, entonces "ä" es lo mismo que "\xc3\xa4".

¿Ha sido útil esta solución?