如何在Visual C++中将字节数组转换为十六进制字符串?

21

方法的声明如下:

//some.h
void TDES_Decryption(BYTE *Data, BYTE *Key, BYTE *InitalVector, int Length);

我正在从下面的代码中调用这个方法:

//some.c
extern "C" __declspec(dllexport) bool _cdecl OnDecryption(LPCTSTR stringKSN, LPCTSTR BDK){
    TDES_Decryption(m_Track1Buffer, m_cryptoKey, init_vector, len);
    return m_Track1Buffer;
}

m_Track1Buffer的数据类型为BYTE m_Track1Buffer[1000]; 现在,我想要对上述方法进行一些更改,即要返回十六进制字符串而不是字节。我应该如何将m_Track1buffer转换为十六进制字符串


什么是“六边形”字符串?这里是不是应该指“十六进制”字符串?请编辑并澄清。此外,提供输入和期望输出的示例总是很有帮助的。 - mvp
5个回答

33

既然您提到了C ++,那么这里是一个答案。Iomanip用于将int以十六进制形式存储到stringstream中。

#include <iomanip>
#include <sstream>
#include <string>

std::string hexStr(const uint8_t *data, int len)
{
     std::stringstream ss;
     ss << std::hex;

     for( int i(0) ; i < len; ++i )
         ss << std::setw(2) << std::setfill('0') << (int)data[i];

     return ss.str();
}

11
你需要使用 setfill('0') 函数来填充 '0' 字符。 - jww
4
为了正确输出每个数字的两位数,我还需要添加std::setw。现在它看起来像这样ss << std::hex << std::setfill('0');ss << std :: setw(2) << static_cast<int>(data[i]); - IFeelGood
如果实现了注释,这个答案就完美了。 - Steve Smith
1
同时,使用static_cast<uint32_t>(static_cast<uint8_t>(data[i]))来支持负数(在许多平台上,char是有符号的)。 - user1119279

11

这段代码将把长度为100的字节数组转换为十六进制字符串:

BYTE array[100];
char hexstr[201];
int i;
for (i=0; i<ARRAY_SIZE(array); i++) {
    sprintf(hexstr+i*2, "%02x", array[i]);
}
hexstr[i*2] = 0;

谢谢您的回答,但我应该如何返回它?我应该在这里返回哪个变量? - Amit Pal
1
@AmitPal 返回类似于 std::string(hexstr) 的东西。 - Felix Dombek

9

这里有一个更灵活的版本(是否使用大写字母?是否在字节之间插入空格?),可以与普通数组和各种标准容器一起使用:

#include <string>
#include <sstream>
#include <iomanip>

template<typename TInputIter>
std::string make_hex_string(TInputIter first, TInputIter last, bool use_uppercase = true, bool insert_spaces = false)
{
    std::ostringstream ss;
    ss << std::hex << std::setfill('0');
    if (use_uppercase)
        ss << std::uppercase;
    while (first != last)
    {
        ss << std::setw(2) << static_cast<int>(*first++);
        if (insert_spaces && first != last)
            ss << " ";
    }
    return ss.str();
}

示例用法(普通数组):

uint8_t byte_array[] = { 0xDE, 0xAD, 0xC0, 0xDE, 0x00, 0xFF };
auto from_array = make_hex_string(std::begin(byte_array), std::end(byte_array), true, true);
assert(from_array == "DE AD C0 DE 00 FF");

使用示例(std::vector):

// fill with values from the array above
std::vector<uint8_t> byte_vector(std::begin(byte_array), std::end(byte_array));
auto from_vector = make_hex_string(byte_vector.begin(), byte_vector.end(), false);
assert(from_vector == "deadc0de00ff");

8
使用循环中的stringstream、sprintf及其他函数根本不是C++。这对性能来说非常糟糕,并且这些函数通常会被频繁调用(除非你只是将一些内容写入日志中)。
以下是一种方法: 直接写入std::string缓冲区是不被推荐的,因为具体的std::string实现可能会有不同的行为,那么这种方式就无法工作,但我们通过这种方式避免了整个缓冲区的一次复制。
#include <iostream>
#include <string>
#include <vector>

std::string bytes_to_hex_string(const std::vector<uint8_t> &input)
{
  static const char characters[] = "0123456789ABCDEF";

  // Zeroes out the buffer unnecessarily, can't be avoided for std::string.
  std::string ret(input.size() * 2, 0);
  
  // Hack... Against the rules but avoids copying the whole buffer.
  auto buf = const_cast<char *>(ret.data());
  
  for (const auto &oneInputByte : input)
  {
    *buf++ = characters[oneInputByte >> 4];
    *buf++ = characters[oneInputByte & 0x0F];
  }
  return ret;
}

int main()
{
  std::vector<uint8_t> bytes = { 34, 123, 252, 0, 11, 52 };
  std::cout << "Bytes to hex string: " << bytes_to_hex_string(bytes) << std::endl;
}

这比预期的解决方案要好得多。您还可以删除向量类型输入,改用指针数组。这将使其更加简洁(需要较少的库)。 - Imtiaz Shakil Siddique
2
你可以使用reserve和back_inserter来完成此操作,而不违反规范。 std :: string ret; ret.reserve(input.size() * 2); auto buf = std :: back_inserter(ret); - Joseph

2

如何使用 Boost 库,可以像这样(从 http://theboostcpplibraries.com/boost.algorithm 中摘取的片段):

#include <boost/algorithm/hex.hpp>
#include <vector>
#include <string>
#include <iterator>
#include <iostream>

using namespace boost::algorithm;

int main()
{
  std::vector<char> v{'C', '+', '+'};
  hex(v, std::ostream_iterator<char>{std::cout, ""});
  std::cout << '\n';

  std::string s = "C++";
  std::cout << hex(s) << '\n';

  std::vector<char> w{'4', '3', '2', 'b', '2', 'b'};
  unhex(w, std::ostream_iterator<char>{std::cout, ""});
  std::cout << '\n';

  std::string t = "432b2b";
  std::cout << unhex(t) << '\n';
}

1
我不确定你是否因为Boost而被downvote,但我认为你的回答是可以接受的,不应该有负分。 - Darrin Cullop
1
对于Qt的替代方案:https://dev59.com/_5bfa4cB1Zd3GeqPngnW - Anssi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接