将十六进制字符串转换为字节数组

ora*_*cal 35 c++ string hex

将可变长度十六进制字符串转换为"01A1"包含该数据的字节数组的最佳方法是什么.

即转换这个:

std::string = "01A1";
Run Code Online (Sandbox Code Playgroud)

进入这个

char* hexArray;
int hexLength;
Run Code Online (Sandbox Code Playgroud)

或这个

std::vector<char> hexArray;
Run Code Online (Sandbox Code Playgroud)

所以当我把hexdump -C它写入文件时,我得到包含的二进制数据01A1.

Nie*_*jes 31

这应该工作:

int char2int(char input)
{
  if(input >= '0' && input <= '9')
    return input - '0';
  if(input >= 'A' && input <= 'F')
    return input - 'A' + 10;
  if(input >= 'a' && input <= 'f')
    return input - 'a' + 10;
  throw std::invalid_argument("Invalid input string");
}

// This function assumes src to be a zero terminated sanitized string with
// an even number of [0-9a-f] characters, and target to be sufficiently large
void hex2bin(const char* src, char* target)
{
  while(*src && src[1])
  {
    *(target++) = char2int(*src)*16 + char2int(src[1]);
    src += 2;
  }
}
Run Code Online (Sandbox Code Playgroud)

根据您的特定平台,可能还有一个标准的实现.

  • @fayyazkl你误解了这个问题 - 这是关于将人类可读的4字符串"01A1"转换为2的内存字节(1和161).因此,显然需要ASCII转换. (2认同)

Chr*_*lli 21

此实现使用内置strtol函数来处理从文本到字节的实际转换,但适用于任何偶数长度的十六进制字符串.

std::vector<char> HexToBytes(const std::string& hex) {
  std::vector<char> bytes;

  for (unsigned int i = 0; i < hex.length(); i += 2) {
    std::string byteString = hex.substr(i, 2);
    char byte = (char) strtol(byteString.c_str(), NULL, 16);
    bytes.push_back(byte);
  }

  return bytes;
}
Run Code Online (Sandbox Code Playgroud)


小智 8

所以为了好玩,我很好奇我是否可以在编译时进行这种转换.它没有很多错误检查,并且在VS2015中完成,它不支持C++ 14 constexpr函数(因此HexCharToInt看起来如何).它采用c字符串数组,将字符对转换为单个字节,并将这些字节扩展为统一初始化列表,用于初始化作为模板参数提供的T类型.T可以替换为类似std :: array的东西来自动返回一个数组.

#include <cstdint>
#include <initializer_list>
#include <stdexcept>
#include <utility>

/* Quick and dirty conversion from a single character to its hex equivelent */
constexpr std::uint8_t HexCharToInt(char Input)
{
    return
    ((Input >= 'a') && (Input <= 'f'))
    ? (Input - 87)
    : ((Input >= 'A') && (Input <= 'F'))
    ? (Input - 55)
    : ((Input >= '0') && (Input <= '9'))
    ? (Input - 48)
    : throw std::exception{};
}

/* Position the characters into the appropriate nibble */
constexpr std::uint8_t HexChar(char High, char Low)
{
    return (HexCharToInt(High) << 4) | (HexCharToInt(Low));
}

/* Adapter that performs sets of 2 characters into a single byte and combine the results into a uniform initialization list used to initialize T */
template <typename T, std::size_t Length, std::size_t ... Index>
constexpr T HexString(const char (&Input)[Length], const std::index_sequence<Index...>&)
{
    return T{HexChar(Input[(Index * 2)], Input[((Index * 2) + 1)])...};
}

/* Entry function */
template <typename T, std::size_t Length>
constexpr T HexString(const char (&Input)[Length])
{
    return HexString<T>(Input, std::make_index_sequence<(Length / 2)>{});
}

constexpr auto Y = KS::Utility::HexString<std::array<std::uint8_t, 3>>("ABCDEF");
Run Code Online (Sandbox Code Playgroud)

  • 我赞成,因为你这样做很开心. (6认同)
  • 太棒了!我想要一种从字符串文字初始化数组的方法,而这几乎正是我所需要的。 (2认同)

Igo*_*gor 8

您可以使用提升:

#include <boost/algorithm/hex.hpp>

char bytes[60] = {0}; 
std::string hash = boost::algorithm::unhex(std::string("313233343536373839")); 
std::copy(hash.begin(), hash.end(), bytes);
Run Code Online (Sandbox Code Playgroud)


Zan*_*ynx 6

你说的是“可变长度”。你的意思是多变?

对于适合 unsigned long 的十六进制字符串,我一直喜欢 C 函数strtoul。要使其转换为十六进制,请传递 16 作为基值。

代码可能如下所示:

#include <cstdlib>
std::string str = "01a1";
unsigned long val = strtoul(str.c_str(), 0, 16);
Run Code Online (Sandbox Code Playgroud)


The*_*CAL 6

这可以通过 a 来完成stringstream,您只需将值存储在中间数字类型中,例如 an int

  std::string test = "01A1"; // assuming this is an even length string
  char bytes[test.length()/2];
  stringstream converter;
  for(int i = 0; i < test.length(); i+=2)
  {
      converter << std::hex << test.substr(i,2);
      int byte;
      converter >> byte;
      bytes[i/2] = byte & 0xFF;
      converter.str(std::string());
      converter.clear();
  }
Run Code Online (Sandbox Code Playgroud)


sam*_*moz 5

如果你想使用 OpenSSL 来做到这一点,我发现了一个漂亮的技巧:

BIGNUM *input = BN_new();
int input_length = BN_hex2bn(&input, argv[2]);
input_length = (input_length + 1) / 2; // BN_hex2bn() returns number of hex digits
unsigned char *input_buffer = (unsigned char*)malloc(input_length);
retval = BN_bn2bin(input, input_buffer);
Run Code Online (Sandbox Code Playgroud)

只要确保去掉字符串的任何前导'0x'。

  • 请务必BN_free (2认同)