如何将hex字符串转换为unsigned char数组?

例如,我有一个cstring "E8 48 D8 FF FF 8B 0D" (包括空格),需要将其转换为等效的无符号字符数组{0xE8,0x48,0xD8,0xFF,0xFF,0x8B,0x0D} 。 有效的方法是什么? 谢谢!

编辑:我不能使用标准库…所以考虑这是一个C问题。 对不起!

你永远不会让我相信这个操作是一个性能瓶颈。 有效的方法是使用标准C库充分利用您的时间:

 static unsigned char gethex(const char *s, char **endptr) { assert(s); while (isspace(*s)) s++; assert(*s); return strtoul(s, endptr, 16); } unsigned char *convert(const char *s, int *length) { unsigned char *answer = malloc((strlen(s) + 1) / 3); unsigned char *p; for (p = answer; *s; p++) *p = gethex(s, (char **)&s); *length = p - answer; return answer; } 

编译和测试。 适用于您的示例。

这回答了原始问题,该问题要求C ++解决方案。

您可以使用带有hex操纵器的istringstream

 std::string hex_chars("E8 48 D8 FF FF 8B 0D"); std::istringstream hex_chars_stream(hex_chars); std::vector bytes; unsigned int c; while (hex_chars_stream >> std::hex >> c) { bytes.push_back(c); } 

请注意, c必须是int (或long ,或其他整数类型),而不是char ; 如果它是一个char (或unsigned char ),将调用错误的>> overload,并从字符串中提取单个字符,而不是hex整数字符串。

额外的错误检查以确保提取的值适合char这将是一个好主意。

  • 遍历所有角色。
    • 如果你有一个hex数字,那么数字是(ch >= 'A')? (ch - 'A' + 10): (ch - '0') (ch >= 'A')? (ch - 'A' + 10): (ch - '0')
      • 将累加器左移四位,并在新数字中添加(或OR)。
    • 如果您有空格,并且前一个字符不是空格,则将当前累加器值附加到数组并将累加器重置为零。

如果您事先知道要解析的字符串的长度(例如,您正在从/ proc读取内容),则可以将sscanf与’hh’类型修饰符一起使用,该修饰符指定下一个转换是diouxX和存储它的指针之一将是signed char或unsigned char。

 // example: ipv6 address as seen in /proc/net/if_inet6: char myString[] = "fe80000000000000020c29fffe01bafb"; unsigned char addressBytes[16]; sscanf(myString, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &addressBytes[0], &addressBytes[1], &addressBytes[2], &addressBytes[3], &addressBytes[4], &addressBytes[5], &addressBytes[6], &addressBytes[7], &addressBytes[8], &addressBytes[9], &addressBytes[10], addressBytes[11],&addressBytes[12], &addressBytes[13], &addressBytes[14], &addressBytes[15]); int i; for (i = 0; i < 16; i++){ printf("addressBytes[%d] = %02x\n", i, addressBytes[i]); } 

输出:

 addressBytes[0] = fe addressBytes[1] = 80 addressBytes[2] = 00 addressBytes[3] = 00 addressBytes[4] = 00 addressBytes[5] = 00 addressBytes[6] = 00 addressBytes[7] = 00 addressBytes[8] = 02 addressBytes[9] = 0c addressBytes[10] = 29 addressBytes[11] = ff addressBytes[12] = fe addressBytes[13] = 01 addressBytes[14] = ba addressBytes[15] = fb 

使用“旧”sscanf()函数:

 string s_hex = "E8 48 D8 FF FF 8B 0D"; // source string char *a_Char = new char( s_hex.length()/3 +1 ); // output char array for( unsigned i = 0, uchr ; i < s_hex.length() ; i += 3 ) { sscanf( s_hex.c_str()+ i, "%2x", &uchr ); // conversion a_Char[i/3] = uchr; // save as char } delete a_Char; 

对于纯C实现,我认为你可以说服sscanf(3)做你喜欢的事情。 我相信这应该是可移植的(包括稍微狡猾的类型强制来安抚编译器),只要你的输入字符串只包含两个字符的hex值。

 #include  #include  char hex[] = "E8 48 D8 FF FF 8B 0D"; char *p; int cnt = (strlen(hex) + 1) / 3; // Whether or not there's a trailing space unsigned char *result = (unsigned char *)malloc(cnt), *r; unsigned char c; for (p = hex, r = result; *p; p += 3) { if (sscanf(p, "%02X", (unsigned int *)&c) != 1) { break; // Didn't parse as expected } *r++ = c; } 

旧的C方式,手工完成;-)(有很多较短的方法,但我不打高尔夫球,我要去运行时)。

 enum { NBBYTES = 7 }; char res[NBBYTES+1]; const char * c = "E8 48 D8 FF FF 8B 0D"; const char * p = c; int i = 0; for (i = 0; i < NBBYTES; i++){ switch (*p){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': res[i] = *p - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': res[i] = *p - 'A' + 10; break; default: // parse error, throw exception ; } p++; switch (*p){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': res[i] = res[i]*16 + *p - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': res[i] = res[i]*16 + *p - 'A' + 10; break; default: // parse error, throw exception ; } p++; if (*p == 0) { continue; } if (*p == ' ') { p++; continue; } // parse error, throw exception } // let's show the result, C style IO, just cout if you want C++ for (i = 0 ; i < 7; i++){ printf("%2.2x ", 0xFF & res[i]); } printf("\n"); 

现在另一个允许数字之间任意数字的数字,任意数量的空格来分隔它们,包括前导或尾随空格(Ben的规格):

 #include  #include  int main(){ enum { NBBYTES = 7 }; char res[NBBYTES]; const char * c = "E8 48 D8 FF FF 8B 0D"; const char * p = c; int i = -1; res[i] = 0; char ch = ' '; while (ch && i < NBBYTES){ switch (ch){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ch -= '0' + 10 - 'A'; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': ch -= 'A' - 10; res[i] = res[i]*16 + ch; break; case ' ': if (*p != ' ') { if (i == NBBYTES-1){ printf("parse error, throw exception\n"); exit(-1); } res[++i] = 0; } break; case 0: break; default: printf("parse error, throw exception\n"); exit(-1); } ch = *(p++); } if (i != NBBYTES-1){ printf("parse error, throw exception\n"); exit(-1); } for (i = 0 ; i < 7; i++){ printf("%2.2x ", 0xFF & res[i]); } printf("\n"); } 

不,它并没有真正混淆......但好吧,看起来确实如此。