如何将无符号字符数组解释为十六进制数组?

How to interpret an unsigned char array as hex array?

我有一个无符号字符数组,我想计算它的 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"

How to interpret an unsigned char array as hex array?

  • 将字符串中的每对十六进制字符转换为字节值。下面的代码通过 复合文字 转换为 3 字节 字符串 ,然后调用 strtoul()

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

    更高级的代码将测试非十六进制字符或 odd/zero 长度的意外存在。


需要更改 CRC 计算

  • 将 CRC 计算更改为基于长度的计算而不是基于字符串的计算。

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

    虽然下面没有编码,但考虑 uint32_t 而不是 crc32() 中的 unsigned int,以便在 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], '[=13=]'}, 0, 16);
  }
  crc = crc32(arr2, len2);
  printf("CRC: 0x%X\n", crc); // 0xB6BA014A instead of 0xBF6B57A2

  return 0;
}

输出

CRC: 0xB6BA014A
CRC: 0xBF6B57A2

OP 原始代码具有未定义的行为,因为它使用 while (message[i] != 0) { 寻找 空字符 ,但 memcpy(arr, str, strlen(str)); 未能提供。