У меня есть реализация кодирования и декодирования 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;
}
Как я могу очистить предупреждения?
Предупреждение присутствует, потому что char на некоторых машинах является знаковым типом. На самом деле это не проблема в программе для действительных входных данных. Обратите внимание, что эта библиотека некорректно обрабатывает недопустимые входные данные*, что совершенно безумно, учитывая, что строки base64 обычно поступают из внешних источников!!! (* Проблема, обнаруженная в предупреждении, плюс использование неинициализированных значений в decoding_table. И, конечно же, полное отсутствие отчетов об ошибках.)
@ikegami, спасибо, а что мне следует изменить, чтобы больше не показывать это предупреждение?
Предупреждение касается использования char в качестве индекса по причине, которую я уже указал. Поэтому не используйте char в качестве индекса.
@LimeStone, суть моего предыдущего комментария заключалась не в том, что вам следует сжимать внешний файл, на который вы ссылаетесь. Речь шла о том, что соответствующее содержимое этого файла должно быть уменьшено до MRE и отредактировано в самом вопросе, чтобы сделать вопрос самодостаточным.
@ikegami братан, большое спасибо, я преобразовал эти данные[i++] в int, например (int)data[i++], и предупреждение больше не показывалось. Спасибо!
@Lime Stone, почему для decoding_table выделено 256, а заполнено только 64?
@chux-ReinstateMonica я не знаю, я получил это из веб-источника. спасибо, что указали на это, хотя





@ikegami сэкономил свое время и спас меня: предупреждение больше не отображается при преобразовании данных[i++] в int, например (int)data[i++].
Однако на самом деле это не решает проблему, на которую пытались обратить ваше внимание предупреждения. Если ваши данные содержат отрицательные значения, они по-прежнему будут отрицательными после преобразования в int. Если вы хотите устранить предупреждения путем преобразования данных, лучшим типом преобразования будет unsigned char.
@JohnBollinger большое спасибо. то же самое, если я конвертирую в unsigned int вместо unsigned char?
Если вы преобразуете в unsigned int вместо unsigned char, то отрицательные входные данные будут преобразованы в числа, намного большие, чем самый большой действительный индекс в массиве, настроенном в *decoding_table. Преобразование в unsigned char — лучший способ заставить его работать одинаково независимо от того, подписан ли char или нет.
Среди предупреждений 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 — это лишь одна из нескольких вещей, которые вам не нравятся в том, на что вы смотрите.
окей, спасибо, что нашли время написать это.
Код, о котором вы спрашиваете, должен быть представлен как минимально воспроизводимый пример в самом вопросе. Очевидно, это будет часть вашего
base64.h, в районе строк 123-126.