二进制字符串到十六进制 c++
Posted
技术标签:
【中文标题】二进制字符串到十六进制 c++【英文标题】:Binary String to Hex c++ 【发布时间】:2015-05-26 10:27:00 【问题描述】:将二进制字符串更改为十六进制时,我只能根据我找到的答案将其设置为特定大小。但是我想以比这更有效的方式将 MASSIVE 二进制字符串更改为完整的十六进制字符串,这是我遇到的唯一完全做到这一点的方法:
for(size_t i = 0; i < (binarySubVec.size() - 1); i++)
string binToHex, tmp = "0000";
for (size_t j = 0; j < binaryVecStr[i].size(); j += 4)
tmp = binaryVecStr[i].substr(j, 4);
if (!tmp.compare("0000")) binToHex += "0";
else if (!tmp.compare("0001")) binToHex += "1";
else if (!tmp.compare("0010")) binToHex += "2";
else if (!tmp.compare("0011")) binToHex += "3";
else if (!tmp.compare("0100")) binToHex += "4";
else if (!tmp.compare("0101")) binToHex += "5";
else if (!tmp.compare("0110")) binToHex += "6";
else if (!tmp.compare("0111")) binToHex += "7";
else if (!tmp.compare("1000")) binToHex += "8";
else if (!tmp.compare("1001")) binToHex += "9";
else if (!tmp.compare("1010")) binToHex += "A";
else if (!tmp.compare("1011")) binToHex += "B";
else if (!tmp.compare("1100")) binToHex += "C";
else if (!tmp.compare("1101")) binToHex += "D";
else if (!tmp.compare("1110")) binToHex += "E";
else if (!tmp.compare("1111")) binToHex += "F";
else continue;
hexOStr << binToHex;
hexOStr << " ";
它彻底而绝对,但速度很慢。
有没有更简单的方法?
【问题讨论】:
您的代码因二进制未对齐 4 位而失败... 我们可以假设输入是 4 位的倍数吗? 我确实说过 "MASSIVE Binary strings" -- 是的,字符串总是 4 的倍数 它与二进制数的质量无关,因为 10000(2) = 10(16) 而不是 80(16) 在 Nx4 8 位字符的缓冲区中流式传输。忘记它们是字符并将缓冲区视为uint32_t *
,然后您可以一次比较32位。比处理字符串和字符要快得多。
【参考方案1】:
更新最后添加了比较和基准
这是另一个基于完美哈希的方法。完美的哈希是使用gperf
生成的(如下所述:Is it possible to map string to int faster than using hashmap?)。
我进一步优化了函数局部静态变量,并将hexdigit()
和hash()
标记为constexpr
。这消除了不必要的任何初始化开销,并为编译器提供了充分的优化空间/
我预计事情不会比这更快。
您可以尝试阅读例如如果可能,一次 1024 个半字节,并让编译器有机会使用 AVX/SSE 指令集对操作进行矢量化。 (我没有检查生成的代码是否会发生这种情况。)
在流模式下将std::cin
转换为std::cout
的完整示例代码是:
#include <iostream>
int main()
char buffer[4096];
while (std::cin.read(buffer, sizeof(buffer)), std::cin.gcount())
size_t got = std::cin.gcount();
char* out = buffer;
for (auto it = buffer; it < buffer+got; it += 4)
*out++ = Perfect_Hash::hexchar(it);
std::cout.write(buffer, got/4);
这是Perfect_Hash
类,通过hexchar
查找稍作编辑和扩展。请注意,它确实使用assert
验证DEBUG
构建中的输入:
Live On Coliru
#include <array>
#include <algorithm>
#include <cassert>
class Perfect_Hash
/* C++ code produced by gperf version 3.0.4 */
/* Command-line: gperf -L C++ -7 -C -E -m 100 table */
/* Computed positions: -k'1-4' */
/* maximum key range = 16, duplicates = 0 */
private:
static constexpr unsigned char asso_values[] =
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 7, 3, 1, 0, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27;
template <typename It>
static constexpr unsigned int hash(It str)
return
asso_values[(unsigned char)str[3] + 2] + asso_values[(unsigned char)str[2] + 1] +
asso_values[(unsigned char)str[1] + 3] + asso_values[(unsigned char)str[0]];
static constexpr char hex_lut[] = "???????????fbead9c873625140";
public:
#ifdef DEBUG
template <typename It>
static char hexchar(It binary_nibble)
assert(Perfect_Hash::validate(binary_nibble)); // for DEBUG only
return hex_lut[hash(binary_nibble)]; // no validation!
#else
template <typename It>
static constexpr char hexchar(It binary_nibble)
return hex_lut[hash(binary_nibble)]; // no validation!
#endif
template <typename It>
static bool validate(It str)
static constexpr std::array<char, 4> vocab[] =
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
'?', '?', '?', '?', '?', '?', '?', '?',
'1', '1', '1', '1', '1', '0', '1', '1',
'1', '1', '1', '0', '1', '0', '1', '0',
'1', '1', '0', '1', '1', '0', '0', '1',
'1', '1', '0', '0', '1', '0', '0', '0',
'0', '1', '1', '1', '0', '0', '1', '1',
'0', '1', '1', '0', '0', '0', '1', '0',
'0', '1', '0', '1', '0', '0', '0', '1',
'0', '1', '0', '0', '0', '0', '0', '0',
;
int key = hash(str);
if (key <= 26 && key >= 0)
return std::equal(str, str+4, vocab[key].begin());
else
return false;
;
constexpr unsigned char Perfect_Hash::asso_values[];
constexpr char Perfect_Hash::hex_lut[];
#include <iostream>
int main()
char buffer[4096];
while (std::cin.read(buffer, sizeof(buffer)), std::cin.gcount())
size_t got = std::cin.gcount();
char* out = buffer;
for (auto it = buffer; it < buffer+got; it += 4)
*out++ = Perfect_Hash::hexchar(it);
std::cout.write(buffer, got/4);
演示输出,例如od -A none -t o /dev/urandom | tr -cd '01' | dd bs=1 count=4096 | ./test
03bef5fb79c7da917e3ebffdd8c41488d2b841dac86572cf7672d22f1f727627a2c4a48b15ef27eb0854dd99756b24c678e3b50022d695cc5f5c8aefaced2a39241bfd5deedcfa0a89060598c6b056d934719eba9ccf29e430d2def5751640ff17860dcb287df8a94089ade0283ee3d76b9fefcce3f3006b8c71399119423e780cef81e9752657e97c7629a9644be1e7c96b5d0324ab16d20902b55bb142c0451e675973489ae4891ec170663823f9c1c9b2a11fcb1c39452aff76120b21421069af337d14e89e48ee802b1cecd8d0886a9a0e90dea5437198d8d0d7ef59c46f9a069a83835286a9a8292d2d7adb4e7fb0ef42ad4734467063d181745aaa6694215af7430f95e854b7cad813efbbae0d2eb099523f215cff6d9c45e3edcaf63f78a485af8f2bfc2e27d46d61561b155d619450623b7aa8ca085c6eedfcc19209066033180d8ce1715e8ec9086a7c28df6e4202ee29705802f0c2872fbf06323366cf64ecfc5ea6f15ba6467730a8856a1c9ebf8cc188e889e783c50b85824803ed7d7505152b891cb2ac2d6f4d1329e100a2e3b2bdd50809b48f0024af1b5092b35779c863cd9c6b0b8e278f5bec966dd0e5c4756064cca010130acf24071d02de39ef8ba8bd1b6e9681066be3804d36ca83e7032274e4c8e8cacf520e8078f8fa80eb8e70af40367f53e53a7d7f7afe8704c 46f58339d660b8151c91bddf82b4096
基准
我想出了三种不同的方法:
-
naive.cpp (no hacks, no libraries);现场拆解on Godbolt
spirit.cpp (Trie);
为了做一些比较,我已经
使用相同的编译器 (GCC 4.9) 和标志 (-O3 -march=native -g0 -DNDEBUG
) 编译它们
优化了输入/输出,因此不会读取 4 个字符/写入单个字符
创建了一个大型输入文件(1 GB)
结果如下:
令人惊讶的是,第一个答案中的naive
方法效果很好
Spirit 在这里做得很糟糕;它的网速为 3.4MB/s,因此整个文件需要 294 秒(!!!)。我们已将其排除在图表之外
naive.cpp 的平均吞吐量约为 720MB/s,perfect.cpp 的平均吞吐量约为 1.14GB/s
这使得完美哈希方法比简单方法快大约 50%。
*总结我想说,10 小时前一时兴起,这种天真的方法非常好as I posted it。如果您真的想要高吞吐量,完美的哈希是一个不错的开始,但可以考虑手动滚动基于 SIMD 的解决方案
【讨论】:
我进一步优化了函数局部静态变量,并将hexdigit()
和hash()
标记为constexpr
。这消除了不必要的任何初始化开销,并为编译器提供了充分的优化空间/
作为旁注,我在authority 上有它的超级骗子性能,手动调整的 SIMD 可以挤出更多的信号。
阻止这种优化的是您在紧密循环中的hash()
调用。它进行了大量的 8 位读取和算术运算。将此与@TonyK 实现中的单机div
指令进行比较。
考虑到constexpr
的广泛使用,我用-O3
编译了这个并反汇编了结果。它比我想象的要近得多。如果我正确地遵循它(优化输出并不容易),那么您的 hash()
实际上正在解析为 2 个 movzbl
指令,这确实使它非常快。我收回我之前的评论。
@AndyBrown 对此表示敬意。我已经添加了比较基准以现在可以回答,包括 Godbolt Compiler Explorer 上 color-coded disassemblies(例如 this one)的实时链接.它似乎确实很快。至少它比天真的方法快:)【参考方案2】:
可能是这样的
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
int main()
std::cout << std::hex << std::stoll("100110110010100100111101010001001101100101010110000101111111111",NULL, 2) << std::endl;
std::stringstream ss;
ss << std::hex << std::stoll("100110110010100100111101010001001101100101010110000101111111111", NULL, 2);
std::cout << ss.str() << std::endl;
return 0;
【讨论】:
这将如何支持“MASSIVE Binary strings”? (重点不是我的) 这是我找到的解决方案之一——P.S.为不重视强调而欢呼:P【参考方案3】:我会这样做:
找到最小的正整数n
,使得这些整数都有不同的余数模n
:
0x30303030 0x30303031 0x30303130 0x30303131 0x30313030 0x30313031 0x30313130 0x30313131 0x31303030 0x31303031 0x31303130 0x31303131 0x31313030 0x31313031 0x31313130 0x31313131
这些是 "0000","0001" 等的 ASCII 表示。我按顺序列出了它们,假设你的机器是大端的;如果它是 little-endian,则表示例如“0001”将是 0x31303030,而不是 0x30303031。您只需执行一次。 n
不会很大——我希望它小于 100。
-
使用
HexChar[0x30303030 % n] = '0', HexChar[0x30303031 % n] = '1'
等(或HexChar[0x31303030 % n] = '1'
等,如果您的机器是小端序)构建表char HexChar[n]
。
现在转换速度快如闪电(我假设sizeof (int) = 4
):
unsigned int const* s = binaryVecStr[a].c_str();
for (size_t i = 0; i < binaryVecStr[a].size(); i += 4, s++)
hexOStr << HexChar[*s % n];
【讨论】:
很不错的一个模组解决方案。当我考虑一次 32 位的比较时,我还尝试提出一种算术/位移方法来减少对表的比较。虽然从来没有想过mod。我喜欢它。 这给了我这个想法,你的想法在概念上接近完美的哈希值。我went and implemented that:LUT 是 26 个项目 - 这不是很多开销)并且所有机器都是constexpr
。
你的幻数“n”是 18。在紧密循环中只有一个“%”,我看不出它怎么会变得更快。在 x86 汇编语言中,余数作为 div
指令的一部分返回,所以这个方法应该是最优的。【参考方案4】:
UPDATE2 请参阅 here for my perfect-hash based solution。我更喜欢这个解决方案,因为
编译速度快很多 它具有更可预测的运行时间(分配为零,因为所有数据都是静态的)EDIT 事实上,现在基准测试显示完美的哈希解决方案比 Spirit 方法大约快 340 倍。 See here:
更新
添加了 Trie-based solution。
这里的查找表使用 Boost Spirit 的内部 Trie 实现进行快速查找。
当然用例如替换out
如果您愿意,可以将向量 back_inserter
或 ostreambuf_iterator<char>
放入您的字符串流中。现在它从不分配甚至 4 个字符(当然,查找表只分配一次)。
您还可以用任何可用的输入范围轻松替换输入迭代器,而无需更改其余代码的一行。
Live On Coliru
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
int main()
std::ostreambuf_iterator<char> out(std::cout);
qi::symbols<char, char> lookup_table;
lookup_table.add
("0000", '0')
("0001", '1')
("0010", '2')
("0011", '3')
("0100", '4')
("0101", '5')
("0110", '6')
("0111", '7')
("1000", '8')
("1001", '9')
("1010", 'a')
("1011", 'b')
("1100", 'c')
("1101", 'd')
("1110", 'e')
("1111", 'f')
;
boost::spirit::istream_iterator bof(std::cin), eof;
if (qi::parse(bof, eof, +lookup_table [ *boost::phoenix::ref(out) = qi::_1 ]))
return 0;
else
return 255;
当使用od -A none -t o /dev/urandom | tr -cd '01' | dd bs=1 count=4096 | ./test
之类的随机数据进行测试时,您会得到
dfc87abf674d8fdb28ed2e36d8ac99faa9c9c4a8aa2253763510482c887e07b2e24cf36ecb7abdcb31521becca54ba1c2ff4be0399f76c2ca28c87fe13a735a0f8031959e5ed213a5d02fb71cbf32b978d2ee9e390a0e2fc6b65b24b2922fb7554a9b211ca1db1b757d1cd0b468d1cd399b114f4f8ef93ade4f33a18bcdb25e2b8138dcd7ec7ef7d2a53f905369c261e19556356ab96f0608bd07f908d3430d3fe7ec21a234c321cc79788f934250da6d2d8e2cb51173ad64ffb4769e7a28224e9bc68123249bbd9c19c01ebbdf2fe4824fb854cf018268d7a988bfd0169f395b30937230733e0f17ba3d8f979341ebde6ff48aac764c2a460625a3ec1349351fe15c8cd4cd3e2933a2840392e381e3c8fc69456eaaf4e8257837f92124e8918a071d7a569fba5e7b189831aa761b3a63feb45d317b1724c53659c00bc82ce7a0c4bcbdc196bc5c990eddc70248d49cc419721d82714256ed13568c4f0740efe42401b0ce644dceaf3507e4acae718265101562f81c237ea8551d051cba38a087fc260af83e123f774e8da956d885d0f87e72e336d8599631f3a44d30676088149b5a1292ecc8682cfbd6982bc37b7e6a5c44f42fcfaabd32c29696a6985fdca5bd6c986dfd4670c4456ac0a7e6ae50ba4218e090f829a2391dd9fc863b31c05a P>
老,初级答案:
从流中读取输入,每 4 个字节输出一个字符。
这里是要点:
char nibble[4];
while (std::cin.read(nibble, 4))
std::cout << "0123456789abcdef"[
(nibble[0]!='0')*8 +
(nibble[1]!='0')*4 +
(nibble[2]!='0')*2 +
(nibble[3]!='0')*1
];
您确实可以将转换设为查找表。不要使用地图,因为它是基于树的,最终会追逐很多指针。不过,boost::flat_map
可能没问题。
【讨论】:
添加了一个基于 trie 的解决方案,它永远不会在内存中分配更多甚至 4 个字节。输入和输出是流式传输的。我现在测试了查找表。看到它Live On Coliru【参考方案5】:我有一种奇怪的感觉,我一定错过了这里问题的重要内容。乍一看,这似乎应该可行:
template <class RanIt, class OutIt>
void make_hex(RanIt b, RanIt e, OutIt o)
static const char rets[] = "0123456789ABCDEF";
if ((e-b) %4 != 0)
throw std::runtime_error("Length must be a multiple of 4");
while (b != e)
int index =
((*(b + 0) - '0') << 3) |
((*(b + 1) - '0') << 2) |
((*(b + 2) - '0') << 1) |
((*(b + 3) - '0') << 0);
*o++ = rets[index];
b += 4;
至少临时来说,这似乎应该与任何事情一样快——在我看来,它接近于达到输出所需的每个输入的最低处理量。
为了最大限度地提高速度,它确实最大限度地减少了对输入的错误检查(甚至可能低于)最低限度。您当然可以确保输入中的每个字符都是“0”或“1”,具体取决于减法的结果。或者,您可以很容易地使用(*(b + 0) != '0') << 3
将0
视为0,将其他任何内容视为1
。同样,您可以使用:(*(b + 0) == '1') << 3
将 1
视为 1,将其他任何内容视为 0。
代码确实避免了计算每个 index
值所需的 4 次计算之间的依赖关系,因此智能编译器应该可以并行执行这些计算。
由于它只适用于迭代器,它避免了输入数据的额外副本,例如(例如)几乎任何使用substr
的东西都可以(尤其是不包括短字符串优化的std::string
的实现) )。
无论如何,使用 this 看起来像这样:
int main()
char input[] = "0000000100100011010001010110011110001001101010111100110111101111";
make_hex(input, input+64, std::ostream_iterator<char>(std::cout));
由于它确实使用了迭代器,它可以很容易(仅举一个明显的例子)从 istreambuf_iterator 获取输入以直接处理来自文件的数据。不过,这很少是最快的方法——使用istream::read
读取大块,使用ostream::write
一次写入大块,您通常会获得更快的速度。不过,这不会影响实际的转换代码——您只需将指针传递到输入和输出缓冲区,它就会将它们用作迭代器。
【讨论】:
你的版本在逻辑上接近我的“天真”。但不知何故,它与完美的哈希解决方案一样快。我稍后会看看为什么。暂时向我 +1 如何更改char input[] = ...
的输入?【参考方案6】:
这似乎行得通。
std::vector<char> binaryVecStr = '0', '0', '0', '1', '1', '1', '1', '0' ;
string binToHex;
binToHex.reserve(binaryVecStr.size()/4);
for (uint32_t * ptr = reinterpret_cast<uint32_t *>(binaryVecStr.data()); ptr < reinterpret_cast<uint32_t *>(binaryVecStr.data()) + binaryVecStr.size() / 4; ++ptr)
switch (*ptr)
case 0x30303030:
binToHex += "0";
break;
case 0x31303030:
binToHex += "1";
break;
case 0x30313030:
binToHex += "2";
break;
case 0x31313030:
binToHex += "3";
break;
case 0x30303130:
binToHex += "4";
break;
case 0x31303130:
binToHex += "5";
break;
case 0x30313130:
binToHex += "6";
break;
case 0x31313130:
binToHex += "7";
break;
case 0x30303031:
binToHex += "8";
break;
case 0x31303031:
binToHex += "9";
break;
case 0x30313031:
binToHex += "A";
break;
case 0x31313031:
binToHex += "B";
break;
case 0x30303131:
binToHex += "C";
break;
case 0x31303131:
binToHex += "D";
break;
case 0x30313131:
binToHex += "E";
break;
case 0x31313131:
binToHex += "F";
break;
default:
// invalid input
binToHex += "?";
std::cout << binToHex;
注意,使用的假设很少:
1) char 有 8 位(并非所有平台都如此)
2) 它需要小端(意味着它至少在 x86、x86_64 上工作)
它假定 binaryVecStr 是 std::vector,但也适用于字符串。它假设binaryVecStr.size() % 4 == 0
【讨论】:
您仍然为整个缓冲区保留内存,如果流大小变大(例如,大于可用内存),这将成为一个障碍 我这样做了,并根据我的解决方案对其进行了基准测试(有关更多结果,请参阅我的答案)。当我在同一个测试平台中使用针对流 IO 优化的代码时,它是ran at ~314MB/s。至少输出是 correct 没有修复(我只是将十六进制数字设为小写,因此我可以校验结果以验证正确性)。以下是用于基准测试的准确代码:Live On Coliru 好吧,1.14GB/s 相当可观。关于我的解决方案,我对它这么慢有点失望:/ 我不确定。我猜这是分支:goo.gl/2Xg1Hw。虽然它并没有那么慢 :) 大多数解决方案都相当慢【参考方案7】:这是我能想到的最快的:
#include <iostream>
int main(int argc, char** argv)
char buffer[4096];
while (std::cin.read(buffer, sizeof(buffer)), std::cin.gcount() > 0)
size_t got = std::cin.gcount();
char* out = buffer;
for (const char* it = buffer; it < buffer + got; it += 4)
unsigned long r;
r = it[3];
r += it[2] * 2;
r += it[1] * 4;
r += it[0] * 8;
*out++ = "0123456789abcdef"[r - 15*'0'];
std::cout.write(buffer, got / 4);
根据@sehe 的基准,在这个问题上它比其他任何东西都快。
【讨论】:
【参考方案8】:至于一个简单的方法,我认为这个很简洁:
std::string bintxt_2_hextxt(const std::string &bin)
std::stringstream reader(bin);
std::stringstream result;
while (reader)
std::bitset<8> digit;
reader >> digit;
result << std::hex << digit.to_ulong();
return result.str();
我不知道应该从哪里读取您的数据,所以我使用了std::string
作为输入数据;但如果它来自文本文件或数据流,将reader
更改为std::ifstream
应该不会很麻烦。
小心!我不知道如果流字符不能被 8 整除会发生什么,而且我还没有测试过这段代码的性能。
Live example
【讨论】:
正如所写,这有几个问题。吞吐量大约为 8.5MB/s,您可以在我的回答中进行比较。我用它来进行基准测试:Live On Coliru。看看你是否能找到解决的问题(除了支持流媒体):) @sehe 总是很高兴学习如何改进代码,非常感谢(感谢您的帮助而不是投反对票):D【参考方案9】:你可以试试二叉决策树:
string binToHex;
for (size_t i = 0; i < binaryVecStr[a].size(); i += 4)
string tmp = binaryVecStr[a].substr(i, 4);
if (tmp[0] == '0')
if (tmp[1] == '0')
if (tmp[2] == '0')
if tmp[3] == '0')
binToHex += "0";
else
binToHex += "1";
else
if tmp[3] == '0')
binToHex += "2";
else
binToHex += "3";
else
if (tmp[2] == '0')
if tmp[3] == '0')
binToHex += "4";
else
binToHex += "5";
else
if tmp[3] == '0')
binToHex += "6";
else
binToHex += "7";
else
if (tmp[1] == '0')
if (tmp[2] == '0')
if tmp[3] == '0')
binToHex += "8";
else
binToHex += "9";
else
if tmp[3] == '0')
binToHex += "A";
else
binToHex += "B";
else
if (tmp[2] == '0')
if tmp[3] == '0')
binToHex += "C";
else
binToHex += "D";
else
if tmp[3] == '0')
binToHex += "E";
else
binToHex += "F";
hexOStr << binToHex;
您可能还想考虑更紧凑的表示 同一个决策树,比如
string binToHex;
for (size_t i = 0; i < binaryVecStr[a].size(); i += 4)
string tmp = binaryVecStr[a].substr(i, 4);
binToHex += (tmp[0] == '0' ?
(tmp[1] == '0' ?
(tmp[2] == '0' ?
(tmp[3] == '0' ? "0" : "1") :
(tmp[3] == '0' ? "2" : "3")) :
(tmp[2] == '0' ?
(tmp[3] == '0' ? "4" : "5") :
(tmp[3] == '0' ? "6" : "7"))) :
(tmp[1] == '0' ?
(tmp[2] == '0' ?
(tmp[3] == '0' ? "8" : "9") :
(tmp[3] == '0' ? "A" : "B")) :
(tmp[2] == '0' ?
(tmp[3] == '0' ? "C" : "D") :
(tmp[3] == '0' ? "E" : "F"))));
hexOStr << binToHex;
更新:在 ASCII 到整数解决方案的脉络中:
unsigned int nibble = static_cast<unsigned int*>(buffer);
nibble &= 0x01010101; // 0x31313131 --> 0x01010101
nibble |= (nibble >> 15); // 0x01010101 --> 0x01010303
nibble |= (nibble >> 6); // 0x01010303 --> 0x0105070C
char* hexDigit = hexDigitTable[nibble & 15];
hexDigitTable
(char[16]
类型)的内容取决于是否
您使用的是 little-endian 或 big-endian 机器。
【讨论】:
使用这个测试程序,我已经将此解决方案的基准测试为 ~307MB/s。当然,循环中的字符串构造会不必要地减慢它的速度。看到它Live On Coliru(以及反汇编goo.gl/KYvUxb) @sehe 这是一个远没有你那么雄心勃勃的答案,这是肯定的!我只是开始做一件事,那就是减少每个循环执行的“ifs”的数量,而无需真正重新考虑程序的逻辑。一个小而快速的优化。改变字符串的构建方式也是一件好事。你在哪里做的基准测试? 在我的工作站上。我目前正在修复最后输入块处理中的一个错误(没有注意到,因为 4 GB 是 4 KB 的倍数)以上是关于二进制字符串到十六进制 c++的主要内容,如果未能解决你的问题,请参考以下文章