【问题标题】:C++ how to convert unsigned char array to string?C ++如何将无符号字符数组转换为字符串?
【发布时间】:2019-09-16 23:36:07
【问题描述】:

我正在测试一段对二进制文件执行哈希运算 (sha256) 的代码,我得到了这样的结果:

for(i = 0; i < SHA256_DIGEST_LENGTH; i++) printf("%02x", c[i]);

这会打印如下内容:

12b64492d18aa37d609f27cb02ce5ba381068d1ef5625193df68451c650a2b8d

我在问如何才能将下面显示的字符串转换为 C++ 中的字符串变量。

谢谢

【问题讨论】:

  • 如果你喜欢printf,还有sprintf。如果你喜欢 iostreams,还有 stringstream。

标签: c++ string sha


【解决方案1】:
#include <iomanip>
#include <sstream>
#include <string>
std::ostringstream oss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; ++i) 
{
      oss << std::hex << std::setw(2) << std::setfill('0') << +c[i];
}
auto str = oss.str();

【讨论】:

  • 为什么是auto 而不是string
【解决方案2】:

要打印出十六进制值,可以使用std::hex 格式;要设置宽度和填充字符,请使用 std::setwstd::setfill,它们是 &lt;iomanip&gt; 的一部分。 由于您没有显示c 的数据类型,我想/建议使用无符号整数类型,例如unsigned char。我稍微修改了代码以使其独立):

#define SHA256_DIGEST_LENGTH 256

#include <iostream>
#include <sstream>
#include <iomanip>

int main() {

    unsigned char c[SHA256_DIGEST_LENGTH];
    for (unsigned int i=0; i<SHA256_DIGEST_LENGTH; i++)
        c[i]=i;

    std::stringstream ss;
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        ss << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)c[i];
    }

    std::cout << ss.str();
}

输出:

000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff

【讨论】:

  • 这只是打印循环索引,而不是 OP 要转换的源数组中的字符...
  • @underscore_d:对;我只是想演示一下std::hex的用法,由于OP没有指定c的类型,所以我重写了那部分。但是:现在调整答案以对c 的类型提出建议。
【解决方案3】:

只是为了比较,这里是sprintf 版本:

#include <stdio.h>
#include <string>

std::string ss;
ss.resize(SHA256_DIGEST_LENGTH * 2 + 1); // includes space for terminating NUL
int used = 0;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    used += sprintf(&ss[used], "%02x", c[i]);
ss.resize(used);

请注意,由于使用了最终的确切大小,因此使缓冲区大于所需的大小并没有什么害处,但如果缓冲区有任何可能太小,则必须使用 snprintf 并传递剩余的缓冲区空间(@ 987654324@).

【讨论】:

  • 我会使用char[] 来接收格式化数据,然后从char[] 构造一个string
  • @RemyLebeau:这没有任何好处,std::stringchar[] 的智能指针包装器,即使您使用静态大小的本地数组,您仍然会卡在一个额外的副本。我展示的方式更好。为了提高效率,放弃sprintf 调用(它必须解析格式字符串),只需将两个char 分配,对应于高半字节和低半字节,直接进入std::string
  • 我想从技术上讲,原始分配的数组的优点是您可以获得未初始化的空间然后写入您想要的内容 - 而 C++ 容器需要您resize() 并因此在新的覆盖之前的容量,或者reserve() 然后emplace_/push_back() 一块一块地,使库检查capacity,每次递增size,等等。不过,我通常怀疑它是否重要,因此 C++ 版本的额外安全性和可读性在这种情况下胜出。
猜你喜欢
  • 1970-01-01
  • 2013-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 2018-09-13
相关资源
最近更新 更多