Hex_string to uint8_t msg[]

Hex_string to uint8_t msg[]

本文关键字:msg uint8 string to Hex      更新时间:2023-10-16

我想转换十六进制字符串中的字符

"0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98" 

uint8_t msg[],不明白该怎么做。

看似简单,却一直想不通。我想将每个字符转换为uint8_t十六进制值。例如,如果我有

string result = "0123456789abcdef";

如何将字符串转换为:

uint8_t msg[] = "0123456789abcdef";

这个函数(感谢将十六进制字符串转换为字节数组)

vector<uint8_t> HexToBytes(const string& hex) {
vector<uint8_t> bytes;
for (unsigned int i = 0; i < hex.length(); i += 2) {
string byteString = hex.substr(i, 2);
uint8_t byte = (uint8_t) strtol(byteString.c_str(), nullptr, 16);
bytes.push_back(byte);
}
return bytes;
}

使用上面的函数,我们得到字节向量并调用方法 data()

我要感谢社区,现在一切正常。感谢您的评论,我已经绝望了,我不能做这么简单的事情。 特别感谢@johnny拖把

编辑 - 更新为就绪字节而不是字符

与其使用.substr()并调用 Cstrtol并强制转换为uint8_t,不如简单地使用istringstreamstd::setbase(16)将字节作为unsigned值直接读取到vector<uint8_t> msg中。参见 std::setbase。

例如,您可以从包含十六进制字符的字符串创建一个istringstream,然后与uint8_t向量和临时unsigned一起直接读取,然后再推回您的向量,例如

std::string result ("0123456789abcdef");    /* input hex string */
std::string s2;                             /* string for 2-chars */
std::istringstream ss (result);             /* stringstream of result */
std::vector<uint8_t> msg;                   /* vector of uint8_t */
while ((ss >> std::setw(2) >> s2)) {    /* read 2-char at a time */
unsigned u;                         /* tmp unsigned value */
std::istringstream ss2 (s2);        /* create 2-char stringstream */
ss2 >> std::setbase(16) >> u;       /* convert hex to unsigned */
msg.push_back((uint8_t)u);          /* add value as uint8_t */
}

这样,使用std::setw(2)读取result每 2 个字符用于创建一个 2 个字符的字符串流,然后使用std::setbase(16)将其转换为unsigned值。一个完整的示例是:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
int main (void) {
std::string result ("0123456789abcdef");    /* input hex string */
std::string s2;                             /* string for 2-chars */
std::istringstream ss (result);             /* stringstream of result */
std::vector<uint8_t> msg;                   /* vector of uint8_t */
while ((ss >> std::setw(2) >> s2)) {    /* read 2-char at a time */
unsigned u;                         /* tmp unsigned value */
std::istringstream ss2 (s2);        /* create 2-char stringstream */
ss2 >> std::setbase(16) >> u;       /* convert hex to unsigned */
msg.push_back((uint8_t)u);          /* add value as uint8_t */
}
std::cout << "string: " << result << "nmsg: n";
for (auto& h : msg) /* for each element of msg, output hex value */
std::cout << "t" << std::setfill('0') << std::hex << std::setw(2) 
<< (uint32_t)h << 'n';;
}

(请注意,输出中需要强制转换,以明确告诉coutuint8_t值视为unsigned值,而不是默认为字符类型的uint8_t值。

示例使用/输出

$ ./bin/hexstr2uint8_t
string: 0123456789abcdef
msg:
01
23
45
67
89
ab
cd
ef

(请注意,这次存储了 8 个uint8_t("字节")值,而不是 16 个字符的值)

这只是使用C++iostream功能的替代方案,它避免了需要投射东西而不是直接调用strtol(在您的情况下,这可能应该strtoul开始)。

手动十六进制转换

在您的最后一条评论中,您指出使用 iostream 和字符串流进行转换很慢。您可以尝试通过消除字符串流并使用string::iterator手动转换每个字符并形成每个uint8_t字节(防止最终半字节或 1/2 字节)来尝试优化一点,例如

#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
/* simple manual conversion of hexchar to value */
uint8_t c2hex (const char c)
{
uint8_t u = 0;
if ('0' <= c && c <= '9')
u = c - '0';
else if ('a' <= c && c <= 'f')
u = c - 'W';
else if ('A' <= c && c <= 'F')
u = c - '7';
else
std::cerr << "error: invalid hex char '" << c << "'n";
return u;
}
int main (void) {
std::string s ("0123456789abcdef");
std::vector<uint8_t> msg;
for (std::string::iterator n = s.begin(); n != s.end(); n += 2) {
uint8_t u = c2hex (*n);             /* save high-nibble */
if (n + 1 != s.end())               /* if low-nibble available */
u = (u << 4) | c2hex (n[1]);    /* shift high left 4 & or */
msg.push_back(u);                   /* store byte in msg */
}
std::cout << "string: " << s << "nmsg:n";
for (auto& h : msg)
std::cout << "t" << std::setfill('0') << std::hex 
<< std::setw(2) << (unsigned)h << 'n';
}

(输出同上)

如果您可以保证字符串中始终存在偶数个字符(仅字节且没有 1/2 字节作为最终奇数字符),则可以通过删除条件并简单地使用以下命令来进一步优化:

uint8_t u = c2hex (n[1]) | (c2hex (*n) << 4);

确保您正在编译完全优化,例如-O3(或-Ofastgcc 版本>= 4.6)在 gcc/clang 上,并使用 VS/Ox

尝试一下并比较性能,您还可以将不同的版本转储到汇编中,看看那里是否有任何其他提示。