обо всем по порядку. Не выполняйте чтение файлов (или любой другой источник) и вычисление CRC в одной и той же функции. Это плохой дизайн. Чтение файлов, как правило, не является полностью независимым от платформы (хотя POSIX - ваш лучший друг), но вычисление CRC может выполняться независимо от платформы. Также вы можете использовать алгоритм CRC для других типов источников данных, к которым нет доступа с помощью fopen()
.
Чтобы дать вам подсказку, функция CRC, которую я всегда добавляю в свои проекты, имеет такой прототип:
uint16_t Crc16(const uint8_t* buffer, size_t size,
uint16_t polynomial, uint16_t crc);
Вам не нужно вызывать функцию один раз и передать ей полное содержимое файла. Вместо этого вы можете просмотреть файл в блоках и вызвать функцию для каждого блока. Аргумент polynomial
в вашем случае - 0xA001
(что, кстати, является многочленом в «обращенной» форме), а аргумент crc
в первый раз устанавливается на 0xFFFF
Каждый раз, когда вы вызываете функцию, вы передаете предыдущее возвращаемое значение функции аргументу crc
.
Во втором фрагменте кода (CRC16_unchar
) вы сначала определяете размер файла, а затем читаете это количество байтов. Не делайте этого, это излишне ограничивает вас для работы с файлами объемом до 4 ГБ (в большинстве случаев). Просто читаю, пока EOF не станет чище ИМХО.
Кроме того, я вижу, что вы боретесь с подписанными / неподписанными байтами. Знаешь что
printf
не знает, передали ли вы целое число со знаком или без знака. Вы говорите printf
с "% d" или "% u", как интерпретировать целое число.
- Даже в самом C практически нет разницы между целым числом со знаком и без знака. C волшебным образом не изменит значение 255 на -1, если вы сделаете
int8_t x = 255
.
См. Этот ансер для получения дополнительной информации о том, когда C использует подпись целого числа: Когда действительно имеет значение подпись целого числа? . Основное правило: всегда используйте uint8_t
для обработки необработанных байтов.
Так что обе функции хороши в отношении размера подписи / целого числа.
РЕДАКТИРОВАТЬ: Как другие пользователи указали в своих ответах, прочитайте файл в блоке вместо байта:
uint16_t CRC16_int(const char* filePath) {
FILE *readFile;
const uint8_t buf[1024];
size_t len;
uint16_t result = 0xffff;;
/* Open a file for reading. */
readFile = fopen(filePath, "rb");
if (readFile == NULL) {
exit(1);
}
/* Read until EOF. */
while ( (len = fread(buf, sizeof(buf), 1, readFile)) > 0 ) {
result = Crc16(buf, len, 0xA001, result);
}
/* readFile could be in error state, check it with ferror() or feof() functions. */
return result;
}
Также вам следует изменить прототип функции, чтобы можно было возвращать ошибку, например ::
// Return true when successful, false on error. CRC is stored in result.
bool CRC16_int(const char* filePath, uint16_t *result)