Какой тип данных лучше в расчете CRC16 для любого типа файла - PullRequest
1 голос
/ 24 февраля 2012

Здесь я использую две разные функции для вычисления CRC16 для любого типа файла (.txt,.tar,.tar.gz,.bin,.scr,.sh etc), и другой размер также варьируется от 1 KB to 5 GB.

Я хочу добиться этого

   `cross platform 

   less time consuming

   Have to work proper for any type of file and any size`

Я получил одинаковое значение CRC в обеих функциях. но любой может сказать мне, какой из них лучше рассчитать CRC16 для любого типа файла любого размера на другой платформе.

Здесь мы должны рассмотреть от 0 до 255 всех символов типа.

Может ли какой-нибудь орган предложить мне, какой из них хорош в моих требованиях.

Код обеих функций:

Первый, который имеет int тип данных в readChar здесь я использую int readChar

int CRC16_int(const char* filePath) {

    //Declare variable to store CRC result.
    unsigned short result;
    //Declare loop variables.
    int intInnerLoopIndex;
    result = 0xffff; //initialize result variable to perform CRC checksum calculation.

    //Store message which read from file.
    //char content[2000000];

    //Create file pointer to open and read file.
    FILE *readFile;

    //Use to read character from file.
    int readChar;

    //open a file for Reading
    readFile = fopen(filePath, "rb");

    //Checking file is able to open or exists.
    if (!readFile) {
        fputs("Unable to open file %s", stderr);
    }
    /*
     Here reading file and store into variable.
     */
    int chCnt = 0;
    while ((readChar = getc(readFile)) != EOF) {

        //printf("charcater is %c\n",readChar);
        //printf("charcater is %c and int is %d \n",readChar,readChar);
        result ^= (short) (readChar);
        for (intInnerLoopIndex = 0; intInnerLoopIndex < 8; intInnerLoopIndex++) {
            if ((result & 0x0001) == 0x0001) {
                result = result >> 1; //Perform bit shifting.
                result = result ^ 0xa001; //Perform XOR operation on result.
            } else {
                result = result >> 1; //Perform bit shifting.
            }
        }

        //content[chCnt] = readChar;
        chCnt++;
    }
    printf("\nCRC data length in file: %d", chCnt);
    //This is final CRC value for provided message.
    return (result);
}

Второй - unsigned char тип данных readChar Здесь я использую unsigned char readChar

int CRC16_unchar(const char* filePath) {

    unsigned int filesize;
    //Declare variable to store CRC result.
    unsigned short result;
    //Declare loop variables.
    unsigned int intOuterLoopIndex, intInnerLoopIndex;
    result = 0xffff; //initialize result variable to perform CRC checksum calculation.
    FILE *readFile;
    //Use to read character from file.
    //The problem is if you read a byte from a file with the hex value (for example) 0xfe, 
    //then the char value will be -2 while the unsigned char value will be 254. 
    //This will significantly affect your CRC 
    unsigned char readChar;
    //open a file for Reading
    readFile = fopen(filePath, "rb");
    //Checking file is able to open or exists.
    if (!readFile) {
        fputs("Unable to open file %s", stderr);
    }
    fseek(readFile, 0, SEEK_END); // seek to end of file
    filesize = ftell(readFile); // get current file pointer
    fseek(readFile, 0, SEEK_SET); // seek back to beginning of file
    /*
     Here reading file and store into variable.
     */
    int chCnt = 0;

    for (intOuterLoopIndex = 0; intOuterLoopIndex < filesize; intOuterLoopIndex++) {
        readChar = getc(readFile);
        printf("charcater is %c and int is %d\n",readChar,readChar);

                result ^= (short) (readChar);
                for (intInnerLoopIndex = 0; intInnerLoopIndex < 8; intInnerLoopIndex++) {
                    if ((result & 0x0001) == 0x0001) {
                        result = result >> 1; //Perform bit shifting.
                        result = result ^ 0xa001; //Perform XOR operation on 
                    } else {
                        result = result >> 1; //Perform bit shifting.
                    }
                }
                chCnt++;
    }
    printf("\nCRC data length in file: %d", chCnt);
    return (result);
}

Пожалуйста, помогите мне разобраться с этой проблемой

Спасибо

Ответы [ 3 ]

2 голосов
/ 24 февраля 2012

обо всем по порядку. Не выполняйте чтение файлов (или любой другой источник) и вычисление 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)
1 голос
/ 24 февраля 2012

Вы хотите читать и записывать 8-битные байты, используя unsigned char вместо простого char, потому что char может быть подписанным или беззнаковым, и это зависит от компилятора (разрешено стандартом C). Таким образом, значение, которое вы получите от getc(), должно быть преобразовано в unsigned char перед использованием в вычислениях CRC. Вы также можете fread() в unsigned char. Если вы работаете с подписанными символами, расширение знака в целых, скорее всего, нарушит ваши вычисления CRC.

Кроме того, в соответствии со стандартом C fseek(FilePtr, 0, SEEK_END) имеет неопределенное поведение для двоичных потоков, и двоичные потоки не обязательно должны поддерживать SEEK_END в fseek(). Однако на практике это обычно работает так, как мы хотим.

Еще одна вещь, которую вы должны рассмотреть, это проверка ошибок ввода / вывода. Ваш код не работает в этом отношении.

0 голосов
/ 24 февраля 2012

Тип данных, с которым вы производите вычисления, на мой взгляд, не должен совпадать с тем, который вы читали из файла.Выполнение одного вызова функции в библиотеке времени выполнения для чтения одного байта просто неэффективно.Вы, вероятно, должны читать порядка 2-4 Кбайт за раз, а затем перебирать каждый возвращенный «кусок» любым способом, который вы выберете.

Также нет абсолютно никакого смысла читать размер файлазаранее вы должны просто читать до тех пор, пока чтение не вернет меньше данных, чем ожидалось, и в этом случае вы можете проверить feof() и ferror(), чтобы выяснить, что делать, обычно просто прекратите работу после завершения.См. Справочную страницу <a href="http://linux.die.net/man/3/fread" rel="nofollow">fread()</a>.

...