Hex_string 到 uint8_t 消息[]
Hex_string to uint8_t msg[]
我想转换十六进制字符串中的字符
"0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98"
到uint8_t msg[]
不明白怎么做。
看似简单,却一直想不通。我想将每个字符转换为 uint8_t
十六进制值。例如,如果我有
string result = "0123456789abcdef";
如何将字符串转换为:
uint8_t msg[] = "0123456789abcdef";
这个函数(感谢 Converting a hex string to a byte array )
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-mopp
编辑 - 更新为就绪字节而不是字符
而不是使用 .substr()
并调用 C strtol
并转换为 uint8_t
,您可以简单地使用 istringstream
和 std::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 字符的字符串流,然后使用 [=19] 将其转换为 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';;
}
(注意 输出中要求的转换明确告诉 cout
将 uint8_t
值视为 unsigned
值而不是uint8_t
值,默认为字符类型。
例子Use/Output
$ ./bin/hexstr2uint8_t
string: 0123456789abcdef
msg:
01
23
45
67
89
ab
cd
ef
(注意 这次存储了 8 个 uint8_t
("byte") 个值而不是 16 个字符值)
它只是使用 C++ iostream 功能的替代方法,它避免了转换而不是直接调用 strtol
(在您的情况下可能应该是 strtoul
开始)。
手动十六进制转换
在您最后的评论中,您指出使用 iostream 和 stringstream 进行转换很慢。您可以尝试通过消除 stringstream 并使用 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
(或 -Ofast
gcc 版本 >= 4.6)在 gcc/clang 和 /Ox
上与 VS.
尝试一下并比较性能,您可以另外将不同的版本转储到程序集,看看那里是否有任何其他提示。
我想转换十六进制字符串中的字符
"0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98"
到uint8_t msg[]
不明白怎么做。
看似简单,却一直想不通。我想将每个字符转换为 uint8_t
十六进制值。例如,如果我有
string result = "0123456789abcdef";
如何将字符串转换为:
uint8_t msg[] = "0123456789abcdef";
这个函数(感谢 Converting a hex string to a byte array )
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-mopp
编辑 - 更新为就绪字节而不是字符
而不是使用 .substr()
并调用 C strtol
并转换为 uint8_t
,您可以简单地使用 istringstream
和 std::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 字符的字符串流,然后使用 [=19] 将其转换为 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';;
}
(注意 输出中要求的转换明确告诉 cout
将 uint8_t
值视为 unsigned
值而不是uint8_t
值,默认为字符类型。
例子Use/Output
$ ./bin/hexstr2uint8_t
string: 0123456789abcdef
msg:
01
23
45
67
89
ab
cd
ef
(注意 这次存储了 8 个 uint8_t
("byte") 个值而不是 16 个字符值)
它只是使用 C++ iostream 功能的替代方法,它避免了转换而不是直接调用 strtol
(在您的情况下可能应该是 strtoul
开始)。
手动十六进制转换
在您最后的评论中,您指出使用 iostream 和 stringstream 进行转换很慢。您可以尝试通过消除 stringstream 并使用 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
(或 -Ofast
gcc 版本 >= 4.6)在 gcc/clang 和 /Ox
上与 VS.
尝试一下并比较性能,您可以另外将不同的版本转储到程序集,看看那里是否有任何其他提示。