たとえば、cstring "E8 48 D8 FF FF 8B 0D"
(スペースを含む)があり、同等のunsignedchar配列{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++ソリューションを要求した元の質問に答えます。
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
)、 間違い >>
オーバーロードが呼び出され、16進整数文字列ではなく、文字列から個々の文字が抽出されます。
抽出された値がchar
内に収まるようにするための追加のエラーチェックは良い考えです。
(ch >= 'A')? (ch - 'A' + 10): (ch - '0')
。事前に解析する文字列の長さがわかっている場合(たとえば、/ procから何かを読み取っている場合)、sscanfを「hh」型修飾子とともに使用できます。これは、次の変換がdiouxXの1つであり、それを格納するためのポインターであることを指定します。符号付き文字または符号なし文字のいずれかになります。
// 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)
に自分が何をするかを説得できると思います。入力文字列に2文字の16進値しか含まれない限り、これは移植可能である必要があると思います(コンパイラをなだめるためのやや危険な型強制を含む)。
#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;
}