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

3

我有一个unsigned char数组,想要计算CRC32校验和。

然而,CRC32函数也需要一个unsigned char指针,但它将数组解释为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,但无符号字符数组必须被解释为十六进制数组。

例如,这是计算CRC的结果:
输入:
"47d46d17e759a1dec810758c08004510002127d90000401152e4c0a8b21fc0a8b2255b9b5b9c000db20caabbccddee00000000000000000000000000"

  • 作为ASCII:0xB6BA014A(这是我通常得到的结果,因为它被解释为ASCII)
  • 作为十六进制:0xBF6B57A2(这是我想要的校验和)

1
听起来你是将输入读取为字符串,而不是将每对字符转换为其表示的十六进制数。很难没有一个 [mcve] 说出来,但似乎你只是向函数传递了错误的数据。 - Retired Ninja
1
或者,您可以在“crc32”内执行十六进制转换:两两检查“message”中的字符。对于每个字符,将其表示的四位准备为十六进制数字。将两个四位值放在一起以形成一个八位值,并在CRC中使用它。 - Eric Postpischil
我无法更改那个。该数组将始终被初始化为非二进制。 - j3141592653589793238
根据@EricPostpischil的建议,您需要更改行byte = message[i];以不使用ASCII值而是使用字节值。请参阅有关如何使用sscanf()的十六进制字符串问题。 - fdk1342
真的。我不知道如何表达。 - j3141592653589793238
显示剩余7条评论
1个回答

2
如何将无符号字符数组解释为十六进制数组?
  • Convert each pair of hexadecimal characters in the string to a byte value. Code below converts via a compound literal to form a 3 byte string, followed by a call to strtoul().

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

    More advanced code would test for the unexpected presence of non-hexadecimal characters or an odd/zero length.

CRC计算需要更改
  • Change CRC calculation to a length based one rather than a string one.

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

    Although not coded below, consider uint32_t instead of unsigned int in crc32() for correct operation when unsigned is not 32-bit.

总的来说
#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;
}

输出

CRC: 0xB6BA014A
CRC: 0xBF6B57A2

OP原始代码存在未定义行为,因为它在while (message[i] != 0) {中寻找一个空字符,但是memcpy(arr, str, strlen(str));没有提供一个。


你把查找表藏在哪里了? - Swordfish
你一定很聪明,那是一个很好的答案。我很欣赏。 - j3141592653589793238
@Swordfish 不太清楚,你指的是哪个“查找表”? - chux - Reinstate Monica
@Swordfish 这个 for (j = 7; j >= 0; j--) { 就是这样做的。通常是速度与代码/数据大小之间的权衡。 - chux - Reinstate Monica
@chux 这样做 - 啊。 - Swordfish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接