场景
- 在开发使用加密算法
md5,sha256等
的功能时, 会生成基于十六进制的字符串密钥。 这时候在使用这些密钥进行解密或加密的时候,第三方库都需要传入一个字节数组usigned char*
格式的数组,它每个字节的高4位和低4位都分别存储了1个字符值。那么用C++
如何实现?
说明
-
举例子比如字符串
"a3fd"
,它有4个字符,那么它实际上只需要2
个字节就可以存储。每两个字符存储在一个字节里,分别对应着高低4位。所以"a3fd"
就是在内存里的结果是{0xa3,0xfd}
。 -
如果是使用
python
的话,bytes
类型的对象默认就有fromhex
方法,很方便,可惜C++
标准库没有这么方便的方法。bytes.fromhex(strData)
-
我们知道标准字符串
string
可以存储任意的字节数据0~0xff
, 它的size()
并不是遇到\0
就会结束。所以可以使用string
来存储字节数组。 -
在
C++11
的<string>
里,增加了一个std::stoi
方法,用来把字符串转换为对应的int
值,也就是之前说的十六进制转换。 使用它来转换两个字符到int
值,再把这个uint8_t
值添加到作为字节数组存储的string
里即可。int stoi( const std::string& str, std::size_t* pos = 0, int base = 10 );
-
注意,这里的十六进制字符串必须是偶数个,如果是奇数个,那么最有一个字符就不清楚是放在高位还是低位。
例子
- 这里分别用
C++11
和C++98
实现了转换的方法。如果是逆转过来,把字节数组转换为十六进制字符串,只需要使用stringstream
作为输入或者sprintf "%.x"
即可,参考ConvertBytesToEvenHexString()
函数.
// test-hex-string-to-byte.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <string>
#include <stdint.h>
#include <iostream>
#include <assert.h>
#include <sstream>
#include <math.h>
using namespace std;
// https://blog.csdn.net/infoworld/article/details/9451591
static uint8_t stoi98(const string& data)
{
auto& first = data[0];
uint8_t f = (first & 0x40)?(first&0x0F)+0x9:(first & 0x0F);
auto& second = data[1];
uint8_t s = (second & 0x40)?(second&0x0F)+0x9:(second & 0x0F);
return ((f << 4) & 0xf0) | (s & 0x0f);
}
static string ConvertEvenHexStringToBytesCpp11(const string& data)
{
string result;
auto size = data.size();
auto count = size / 2;
for(size_t i = 0; i< count; i++){
auto value = (uint8_t)stoi(data.substr(i*2,2),0,16);
result.append(1,value);
}
return result;
}
static string ConvertEvenHexStringToBytesCpp98(const string& data)
{
string result;
auto size = data.size();
auto count = size / 2;
for(size_t i = 0; i< count; i++){
auto sub = data.substr(i*2,2);
auto value = (uint8_t)stoi98(sub.c_str());
result.append(1,value);
}
return result;
}
static string ConvertBytesToEvenHexString(const string& data)
{
stringstream ss;
ss << hex;
for(size_t i = 0; i< data.size(); ++i){
auto& one = data[i];
ss << (one >> 4 & 0x0f) << (one & 0x0f);
}
string result = ss.str();
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
auto str = "a3fd";
auto result = ConvertEvenHexStringToBytesCpp11(str);
auto mResult = "\xa3\xfd";
assert(result.size() == (strlen(str) /2) );
assert(result == mResult);
auto source = ConvertBytesToEvenHexString(result);
cout << source << endl;
assert(str == source);
str = "a3fd7be21c504d8ed7d19b";
result = ConvertEvenHexStringToBytesCpp11(str);
mResult = "\xa3\xfd\x7b\xe2\x1c\x50\x4d\x8e\xd7\xd1\x9b";
assert(result.size() == (strlen(str) /2));
assert(result == mResult);
source = ConvertBytesToEvenHexString(result);
cout << source << endl;
assert(str == source);
str = "a3fd";
result = ConvertEvenHexStringToBytesCpp98(str);
mResult = "\xa3\xfd";
assert(result.size() == (strlen(str) /2));
assert(result == mResult);
source = ConvertBytesToEvenHexString(result);
cout << source << endl;
assert(str == source);
str = "a3fd7be21c504d8ed7d19b";
result = ConvertEvenHexStringToBytesCpp98(str);
mResult = "\xa3\xfd\x7b\xe2\x1c\x50\x4d\x8e\xd7\xd1\x9b";
assert(result.size() == (strlen(str) /2));
assert(result == mResult);
source = ConvertBytesToEvenHexString(result);
cout << source << endl;
assert(str == source);
system("pause");
return 0;
}
输出
a3fd
a3fd7be21c504d8ed7d19b
a3fd
a3fd7be21c504d8ed7d19b