[英]How to turn a hex string into an unsigned char array?
例如,我有一个字符串"E8 48 D8 FF FF 8B 0D"
(包括空格),需要将其转换为等效的无符号字符数组{0xE8,0x48,0xD8,0xFF,0xFF,0x8B,0x0D}
。 什么是有效的方法? 谢谢!
编辑:我不能使用std库...所以考虑这是一个C问题。 对不起!
这回答了原始问题,该问题要求使用C ++解决方案。
您可以将istringstream
与hex
操纵器一起使用:
std::string hex_chars("E8 48 D8 FF FF 8B 0D");
std::istringstream hex_chars_stream(hex_chars);
std::vector<unsigned char> bytes;
unsigned int c;
while (hex_chars_stream >> std::hex >> c)
{
bytes.push_back(c);
}
注意, c
必须是int
(或long
或其他整数类型),而不是char
; 如果它是一个char
(或unsigned char
),则将调用错误的>>
重载,并且将从字符串而不是十六进制整数字符串中提取单个字符。
进行额外的错误检查以确保提取的值适合char
会是一个好主意。
您永远不会说服我该操作是性能瓶颈。 有效的方法是使用标准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;
}
编译和测试。 适用于您的示例。
(ch >= 'A')? (ch - 'A' + 10): (ch - '0')
(ch >= 'A')? (ch - 'A' + 10): (ch - '0')
。
如果您事先知道要解析的字符串的长度(例如,您正在从/ proc中读取内容),则可以将sscanf与'hh'类型修饰符一起使用,该修饰符指定下一个转换是diouxX之一,也是存储它的指针将为签名字符或未签名字符。
// 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)
做什么。 我相信这应该是可移植的(包括稍微狡猾的强制转换,以安抚编译器),只要您的输入字符串只包含两个字符的十六进制值即可。
#include <stdio.h>
#include <stdlib.h>
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 <stdio.h>
#include <stdlib.h>
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");
}
不,它并不是真正令人困惑的...但是,看起来确实如此。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.