C++ 如何将一串十六进制值转换为一个字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3790613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:44:55  来源:igfitidea点击:

How to convert a string of hex values to a string?

c++stringstlascii

提问by NullUserException

Say I have a string like:

假设我有一个字符串:

string hex = "48656c6c6f";

Where every two characters correspond to the hex representation of their ASCII, value, eg:

其中每两个字符对应于其 ASCII 值的十六进制表示,例如:

0x48 0x65 0x6c 0x6c 0x6f = "Hello"

So how can I get "hello"from "48656c6c6f"without having to create a lookup ASCII table? atoi()obviously won't work here.

那么我怎样才能"hello""48656c6c6f"不必创建查找 ASCII 表的情况下获得呢?atoi()显然不会在这里工作。

回答by zwol

Hex digits are very easy to convert to binary:

十六进制数字很容易转换为二进制:

// C++98 guarantees that '0', '1', ... '9' are consecutive.
// It only guarantees that 'a' ... 'f' and 'A' ... 'F' are
// in increasing order, but the only two alternative encodings
// of the basic source character set that are still used by
// anyone today (ASCII and EBCDIC) make them consecutive.
unsigned char hexval(unsigned char c)
{
    if ('0' <= c && c <= '9')
        return c - '0';
    else if ('a' <= c && c <= 'f')
        return c - 'a' + 10;
    else if ('A' <= c && c <= 'F')
        return c - 'A' + 10;
    else abort();
}

So to do the whole string looks something like this:

所以做整个字符串看起来像这样:

void hex2ascii(const string& in, string& out)
{
    out.clear();
    out.reserve(in.length() / 2);
    for (string::const_iterator p = in.begin(); p != in.end(); p++)
    {
       unsigned char c = hexval(*p);
       p++;
       if (p == in.end()) break; // incomplete last digit - should report error
       c = (c << 4) + hexval(*p); // + takes precedence over <<
       out.push_back(c);
    }
}

You might reasonably ask why one would do it this way when there's strtol, and using it is significantly less code (as in James Curran's answer). Well, that approach is a full decimal order of magnitudeslower, because it copies each two-byte chunk (possibly allocating heap memory to do so) and then invokes a general text-to-number conversion routine that cannot be written as efficiently as the specialized code above. Christian's approach (using istringstream) is five times slower than that. Here's a benchmark plot - you can tell the difference even with a tiny block of data to decode, and it becomes blatant as the differences get larger. (Note that both axes are on a log scale.)

您可能会合理地问为什么在有 时会这样做strtol,并且使用它的代码要少得多(如 James Curran 的回答)。嗯,这种方法慢了一个完整的十进制数量级,因为它复制每个两字节的块(可能分配堆内存来这样做)然后调用一个通用的文本到数字转换例程,它不能像上面有专门的代码。Christian 的方法(使用 istringstream)比那个慢五倍。这是一个基准图 - 即使使用一小块要解码的数据,您也可以分辨出差异,并且随着差异变大,差异变得明显。(请注意,两个轴都在对数刻度上。)

Benchmark comparison plot

基准比较图

Is this premature optimization? Hell no. This is the kind of operation that gets shoved in a library routine, forgotten about, and then called thousands of times a second. It needs to scream. I worked on a project a few years back that made very heavy use of SHA1 checksums internally -- we got 10-20% speedups on common operations by storing them as raw bytes instead of hex, converting only when we had to show them to the user -- and that was with conversion functions that had already been tuned to death. One might honestly prefer brevity to performance here, depending on what the larger task is, but if so, why on earth are you coding in C++?

这是过早的优化吗?一定不行。这种操作会被推入库例程中,被遗忘,然后每秒调用数千次。它需要尖叫。几年前我参与了一个在内部大量使用 SHA1 校验和的项目——通过将它们存储为原始字节而不是十六进制,我们在常见操作上获得了 10-20% 的加速,仅在我们必须将它们显示给用户——那是带有已经被调整到死的转换函数。老实说,人们可能更喜欢简洁而不是性能,这取决于更大的任务是什么,但如果是这样,你到底为什么要用 C++ 编码?

Also, from a pedagogical perspective, I think it's useful to show hand-coded examples for this kind of problem; it reveals more about what the computer has to do.

另外,从教学的角度来看,我认为展示针对此类问题的手工编码示例很有用;它揭示了有关计算机必须做什么的更多信息。

回答by James Curran

int len = hex.length();
std::string newString;
for(int i=0; i< len; i+=2)
{
    string byte = hex.substr(i,2);
    char chr = (char) (int)strtol(byte.c_str(), null, 16);
    newString.push_back(chr);
}

回答by András Czigány

I can not comment, but zwol's solution has a bug:

我无法评论,但是 zwol 的解决方案有一个错误:

c = c << 4 + hexval(*p);

is correctly

是正确的

c = (c << 4) + hexval(*p);

as the shift operator has lower precedence than add

因为 shift 运算符的优先级低于 add

回答by Christian Ammer

std::string str("48656c6c6f");
std::string res;
res.reserve(str.size() / 2);
for (int i = 0; i < str.size(); i += 2)
{
    std::istringstream iss(str.substr(i, 2));
    int temp;
    iss >> std::hex >> temp;
    res += static_cast<char>(temp);
}
std::cout << res;

回答by schnaader

strtolshould do the job if you add 0xto each hex digit pair.

如果您添加0x到每个十六进制数字对,strtol应该可以完成这项工作。