Предупреждение: индекс массива имеет тип «char» [-Wchar-subscripts] в C

У меня есть реализация кодирования и декодирования base64 на C. Я ее не делал, я просто скопировал.

Когда я компилирую его с помощью этой команды...

gcc -Wall -g -c main.c

... он выдает следующие предупреждения:

source/base64.h: In function ‘base64_decode’:
source/base64.h:45:75: warning: array subscript has type ‘char’ [-Wchar-subscripts]
   45 |         uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
      |                                                                       ~~~~^~~~~
source/base64.h:46:75: warning: array subscript has type ‘char’ [-Wchar-subscripts]
   46 |         uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
      |                                                                       ~~~~^~~~~
source/base64.h:47:75: warning: array subscript has type ‘char’ [-Wchar-subscripts]
   47 |         uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
      |                                                                       ~~~~^~~~~
source/base64.h:48:75: warning: array subscript has type ‘char’ [-Wchar-subscripts]
   48 |         uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
      |

main.c может быть так же просто, как

#include "base64.h"

Это урезанная версия base64.h, которая выдает следующие предупреждения:

#pragma once
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
 
static const char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
                                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                                'w', 'x', 'y', 'z', '0', '1', '2', '3',
                                '4', '5', '6', '7', '8', '9', '+', '/'};
static char *decoding_table = NULL;
 
void build_decoding_table() {
 
    decoding_table = malloc(256);
 
    for (int i = 0; i < 64; i++)
        decoding_table[(unsigned char) encoding_table[i]] = i;
}
 
 
void base64_cleanup() {
    free(decoding_table);
}
 
 
char *base64_decode(const char *data,
                             size_t input_length) {
 
    if (decoding_table == NULL) build_decoding_table();
    if (input_length % 4 != 0) return NULL;
 
    size_t output_length = input_length / 4 * 3;
    if (data[input_length - 1] == '=') (output_length)--;
    if (data[input_length - 2] == '=') (output_length)--;
 
    char *decoded_data = malloc(output_length+1);
    if (decoded_data == NULL) return NULL;
 
    for (int i = 0, j = 0; i < input_length;) {
 
        uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
        uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
        uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
        uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
 
        uint32_t triple = (sextet_a << 3 * 6)
        + (sextet_b << 2 * 6)
        + (sextet_c << 1 * 6)
        + (sextet_d << 0 * 6);
 
        if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
        if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
        if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
    }
    decoded_data[output_length] = '\0';
 
    return decoded_data;
}

Как я могу очистить предупреждения?

Код, о котором вы спрашиваете, должен быть представлен как минимально воспроизводимый пример в самом вопросе. Очевидно, это будет часть вашего base64.h, в районе строк 123-126.

John Bollinger 21.02.2024 15:44

Предупреждение присутствует, потому что char на некоторых машинах является знаковым типом. На самом деле это не проблема в программе для действительных входных данных. Обратите внимание, что эта библиотека некорректно обрабатывает недопустимые входные данные*, что совершенно безумно, учитывая, что строки base64 обычно поступают из внешних источников!!! (* Проблема, обнаруженная в предупреждении, плюс использование неинициализированных значений в decoding_table. И, конечно же, полное отсутствие отчетов об ошибках.)

ikegami 21.02.2024 15:51

@ikegami, спасибо, а что мне следует изменить, чтобы больше не показывать это предупреждение?

Lime Stone 21.02.2024 15:55

Предупреждение касается использования char в качестве индекса по причине, которую я уже указал. Поэтому не используйте char в качестве индекса.

ikegami 21.02.2024 15:57

@LimeStone, суть моего предыдущего комментария заключалась не в том, что вам следует сжимать внешний файл, на который вы ссылаетесь. Речь шла о том, что соответствующее содержимое этого файла должно быть уменьшено до MRE и отредактировано в самом вопросе, чтобы сделать вопрос самодостаточным.

John Bollinger 21.02.2024 15:58

@ikegami братан, большое спасибо, я преобразовал эти данные[i++] в int, например (int)data[i++], и предупреждение больше не показывалось. Спасибо!

Lime Stone 21.02.2024 16:06

@Lime Stone, почему для decoding_table выделено 256, а заполнено только 64?

chux - Reinstate Monica 21.02.2024 16:24

@chux-ReinstateMonica я не знаю, я получил это из веб-источника. спасибо, что указали на это, хотя

Lime Stone 24.02.2024 20:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
113
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

@ikegami сэкономил свое время и спас меня: предупреждение больше не отображается при преобразовании данных[i++] в int, например (int)data[i++].

Однако на самом деле это не решает проблему, на которую пытались обратить ваше внимание предупреждения. Если ваши данные содержат отрицательные значения, они по-прежнему будут отрицательными после преобразования в int. Если вы хотите устранить предупреждения путем преобразования данных, лучшим типом преобразования будет unsigned char.

John Bollinger 21.02.2024 16:22

@JohnBollinger большое спасибо. то же самое, если я конвертирую в unsigned int вместо unsigned char?

Lime Stone 24.02.2024 23:02

Если вы преобразуете в unsigned int вместо unsigned char, то отрицательные входные данные будут преобразованы в числа, намного большие, чем самый большой действительный индекс в массиве, настроенном в *decoding_table. Преобразование в unsigned char — лучший способ заставить его работать одинаково независимо от того, подписан ли char или нет.

John Bollinger 24.02.2024 23:38
Ответ принят как подходящий

Среди предупреждений GCC, включенных опцией -Wall, есть -Wchar-subscripts, которое заставляет GCC предупреждать об использовании значений (в частности) типа char в качестве индексов массива. Руководство GCC объясняет это так:

Предупреждать, если индекс массива имеет тип char. Это частая причина ошибки, так как программисты часто забывают, что на некоторых машинах этот тип подписан.

На самом деле, похоже, что char чаще является знаковым типом, чем нет.

Ваша функция base64_decode() противоречит этой проверке, поскольку data[i++] несколько раз используется в качестве индекса массива. Если вы можете быть уверены, что входные данные (хранящиеся в data) состоят только из допустимого кода Base64, то это, вероятно, спорный вопрос, поскольку C требует, чтобы все цифры, используемые в каждом известном мне варианте Base64, были представлены положительными значениями. В этом случае вы можете подавить эти предупреждения, не изменяя код, добавив -Wno-char-subscripts в командную строку gcc. Однако это приведет к подавлению этих в целом разумных предупреждений и для остальной части вашей программы, поэтому это немного тяжеловато.

Если вы готовы изменить декодер, то более мягкий подход будет включать добавление преобразований этих проявлений data[i++] в другой целочисленный тип. unsigned char будет лучшим выбором для этого.

С другой стороны, лучшим решением в целом, вероятно, будет выбор лучшей реализации Base64. Индексы char — это лишь одна из нескольких вещей, которые вам не нравятся в том, на что вы смотрите.

окей, спасибо, что нашли время написать это.

Lime Stone 21.02.2024 16:22

Другие вопросы по теме