У меня есть набор тестовых векторов, представленных в виде шестнадцатеричных строк:
MSG: 6BC1BEE22E409F96E93D7E117393172A
MAC: 070A16B46B4D4144F79BDD9DD04A287C
MSG: 6BC1BEE22E409F96E93D7E117393172AAE2D8A57
MAC: 7D85449EA6EA19C823A7BF78837DFADE
и т.д. Мне нужно как-то включить их в программу C++, не требуя слишком большого редактирования. Существуют различные варианты:
- Отредактируйте тестовые векторы вручную в форме
0x6B,0xC1,0xBE,...
- Отредактируйте вручную тестовые векторы в форме "6BC1BEE22E409F96E93D7E117393172A" и напишите функцию, чтобы преобразовать ее в байтовый массив во время выполнения.
- Напишите программу для анализа тестовых векторов и вывода кода C++.
Но в итоге я использовал:
- Пользовательские литералы,
потому что весело. Я определил вспомогательный класс HexByteArray
и пользовательский литеральный оператор HexByteArray operator "" _$ (const char* s)
который анализирует строку вида "0xXX...XX"
, где XX...XX
- четное число шестнадцатеричных цифр. HexByteArray
включает в себя операторы преобразования в const uint8_t*
и std::vector<uint8_t>
. Так что теперь я могу написать, например,
struct {
std::vector<uint8_t> MSG ;
uint8_t* MAC ;
} Test1 = {
0x6BC1BEE22E409F96E93D7E117393172A_$,
0x070A16B46B4D4144F79BDD9DD04A287C_$
} ;
Который работает хорошо. Но теперь вот мой вопрос: могу ли я сделать это и для массивов? Например:
uint8_t MAC[16] = 0x070A16B46B4D4144F79BDD9DD04A287C_$ ;
или даже
uint8_t MAC[] = 0x070A16B46B4D4144F79BDD9DD04A287C_$ ;
Я не вижу, как заставить это работать. Чтобы инициализировать массив, мне, кажется, нужен std::initializer_list
. Но, насколько я могу судить, такой компилятор может создавать только компилятор. Есть идеи?
Вот мой код:
HexByteArray.h
#include <cstdint>
#include <vector>
class HexByteArray
{
public:
HexByteArray (const char* s) ;
~HexByteArray() { delete[] a ; }
operator const uint8_t*() && { const uint8_t* t = a ; a = 0 ; return t ; }
operator std::vector<uint8_t>() &&
{
std::vector<uint8_t> v ( a, a + len ) ;
a = 0 ;
return v ;
}
class ErrorInvalidPrefix { } ;
class ErrorHexDigit { } ;
class ErrorOddLength { } ;
private:
const uint8_t* a = 0 ;
size_t len ;
} ;
inline HexByteArray operator "" _$ (const char* s)
{
return HexByteArray (s) ;
}
HexByteArray.cpp
#include "HexByteArray.h"
#include <cctype>
#include <cstring>
HexByteArray::HexByteArray (const char* s)
{
if (s[0] != '0' || toupper (s[1]) != 'X') throw ErrorInvalidPrefix() ;
s += 2 ;
// Special case: 0x0_$ is an empty array (because 0x_$ is invalid C++ syntax)
if (!strcmp (s, "0"))
{
a = nullptr ; len = 0 ;
}
else
{
for (len = 0 ; s[len] ; len++) if (!isxdigit (s[len])) throw ErrorHexDigit() ;
if (len & 1) throw ErrorOddLength() ;
len /= 2 ;
uint8_t* t = new uint8_t[len] ;
for (size_t i = 0 ; i < len ; i++, s += 2)
sscanf (s, "%2hhx", &t[i]) ;
a = t ;
}
}