Как интерпретировать массив без знака как шестнадцатеричный массив? - PullRequest
0 голосов
/ 01 декабря 2018

У меня есть массив без знака, из которого я хотел бы вычислить контрольную сумму CRC32.

Функция CRC32 также ожидает беззнаковый указатель на символ, однако она интерпретирует массив как массив ASCII.

Это функция CRC:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

unsigned int crc32(unsigned char *message) 
{
   int i, j;
   unsigned int byte, crc, mask;

   i = 0;
   crc = 0xFFFFFFFF;
   while (message[i] != 0) {
      byte = message[i];            // Get next byte.
      crc = crc ^ byte;
      for (j = 7; j >= 0; j--) {    // Do eight times.
         mask = -(crc & 1);
         crc = (crc >> 1) ^ (0xEDB88320 & mask);
      }
      i = i + 1;
   }
   return ~crc;
}

int main(int argc, char **argv)
{
    unsigned char *arr;
    if ((arr = malloc(64)) == NULL) {
        perror("Could not allocate memory");
        exit(EXIT_FAILURE);
    }
    char str[] = "47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000";
    memcpy(arr, str, strlen(str));
    // ...
    unsigned int crc = crc32(arr);
    printf("CRC: 0x%x\n", crc); // 0xB6BA014A instead of 0xBF6B57A2

    return 0;
}

Теперь я бы хотел вычислить CRC32, но массив unsigned char должен интерпретироваться как шестнадцатеричный массив.

F.ex., Это результат вычисленного CRC:
Ввод:
"47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000"

  • как ASCII: 0xB6BA014A (это то, что я обычнополучить, потому что он интерпретируется как ASCII)
  • как Hex .: 0xBF6B57A2 (это контрольная сумма, которую я хочу)

1 Ответ

0 голосов
/ 01 декабря 2018

Как интерпретировать массив без знака в виде шестнадцатеричного массива?

  • Преобразовать каждую пару шестнадцатеричных символов в строке в байтовое значение.Приведенный ниже код преобразуется с помощью составного литерала в 3-байтовую строку с последующим вызовом strtoul().

    //                    v----------------------------------v _compound literal_
    arr2[i / 2] = strtoul((char[3]) {str[i], str[i + 1], '\0'}, 0, 16);
    

    Более сложный код будет проверять неожиданное присутствие не шестнадцатеричных символов или нечетной / нулевой длины.


Необходимы изменения вычисления CRC

  • Измените вычисление CRC на единицу длины, а не на строку.

    // unsigned int crc32(const char *)
    unsigned int crc32(const void *m, size_t len)
    

    Хотя это не закодировано ниже, рассмотрим uint32_t вместо unsigned int in crc32() для правильной работы, когда unsigned не является 32-разрядным.


Всего

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

unsigned int crc32(const void *m, size_t len) {
  const unsigned char *message = m;
  size_t i;
  int j;
  unsigned int byte, crc, mask;

  i = 0;
  crc = 0xFFFFFFFF;
  //while (message[i] != 0) {
  while (i < len) {
    byte = message[i];            // Get next byte.
    crc = crc ^ byte;
    for (j = 7; j >= 0; j--) {    // Do eight times.
      mask = -(crc & 1);
      crc = (crc >> 1) ^ (0xEDB88320 & mask);
    }
    i = i + 1;
  }
  return ~crc;
}

Пример использования

int main() {
  char str[] =
      "47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000";
  size_t len = strlen(str);
  unsigned int crc = crc32(str, len);
  printf("CRC: 0x%X\n", crc); // 0xB6BA014A instead of 0xBF6B57A2

  size_t len2 = (len + 1) / 2;
  unsigned char arr2[len2];
  for (size_t i = 0; i < len; i += 2) {
    arr2[i / 2] = strtoul((char[3]) {str[i], str[i + 1], '\0'}, 0, 16);
  }
  crc = crc32(arr2, len2);
  printf("CRC: 0x%X\n", crc); // 0xB6BA014A instead of 0xBF6B57A2

  return 0;
}

Output

CRC: 0xB6BA014A
CRC: 0xBF6B57A2

Исходный код OP имел неопределенное поведение в том смысле, что он искал нулевой символ с while (message[i] != 0) {, но memcpy(arr, str, strlen(str)); не смог предоставить один.

...