Шестнадцатеричная строка в uint8_t сообщение [] - PullRequest
2 голосов
/ 01 апреля 2019

Я хочу преобразовать символы в шестнадцатеричной строке

"0b7c28c9b7290c98d7438e70b3d3f7c848fbd7d1dc194ff83f4f7cc9b1378e98" 

в uint8_t msg[] и не понимаю, как это сделать.

Кажется простым, но не смог понять этоиз.Я хочу преобразовать каждый символ в шестнадцатеричное значение uint8_t.Например, если у меня есть

string result = "0123456789abcdef";

Как мне преобразовать строку в:

uint8_t msg[] = "0123456789abcdef";

Ответы [ 2 ]

0 голосов
/ 01 апреля 2019

Редактировать - Обновлены до готовых байтов, а не символов

Вместо того, чтобы использовать .substr() и вызывать C strtol и приводить к uint8_t, вы можете просто использовать istringstreamвместе с std::setbase(16) для чтения байтов как unsigned значений непосредственно в vector<uint8_t> msg.См. std :: setbase .

Например, вы можете создать istringstream из вашей строки, содержащей шестнадцатеричные символы, а затем вместе с вашим вектором uint8_t и временным unsigned для непосредственного чтения, прежде чем вставить обратно в вектор, который вы можете сделать, например,

    std::string result ("0123456789abcdef");    /* input hex string */
    std::string s2;                             /* string for 2-chars */
    std::istringstream ss (result);             /* stringstream of result */
    std::vector<uint8_t> msg;                   /* vector of uint8_t */

    while ((ss >> std::setw(2) >> s2)) {    /* read 2-char at a time */
        unsigned u;                         /* tmp unsigned value */
        std::istringstream ss2 (s2);        /* create 2-char stringstream */
        ss2 >> std::setbase(16) >> u;       /* convert hex to unsigned */
        msg.push_back((uint8_t)u);          /* add value as uint8_t */
    }

Таким образом, каждые 2 символа в result, считываемых с использованием std::setw(2), используются для создания 2-символьного потока строкзатем преобразуется в значение unsigned с использованием std::setbase(16).Полный пример:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>

int main (void) {

    std::string result ("0123456789abcdef");    /* input hex string */
    std::string s2;                             /* string for 2-chars */
    std::istringstream ss (result);             /* stringstream of result */
    std::vector<uint8_t> msg;                   /* vector of uint8_t */

    while ((ss >> std::setw(2) >> s2)) {    /* read 2-char at a time */
        unsigned u;                         /* tmp unsigned value */
        std::istringstream ss2 (s2);        /* create 2-char stringstream */
        ss2 >> std::setbase(16) >> u;       /* convert hex to unsigned */
        msg.push_back((uint8_t)u);          /* add value as uint8_t */
    }

    std::cout << "string: " << result << "\nmsg: \n";
    for (auto& h : msg) /* for each element of msg, output hex value */
        std::cout << "\t" << std::setfill('0') << std::hex << std::setw(2) 
                    << (uint32_t)h << '\n';;
}

( note приведение, требуемое в выходных данных, чтобы явно указать cout, что нужно обрабатывать значение uint8_t как значение unsigned вместоuint8_t значение, которое по умолчанию соответствует типу символа.

Пример Использование / Вывод

$ ./bin/hexstr2uint8_t
string: 0123456789abcdef
msg:
        01
        23
        45
        67
        89
        ab
        cd
        ef

( note имеется 8uint8_t ("byte") значения, хранящиеся в этот раз вместо 16-значных символов)

Это просто альтернатива, использующая функции Cost iostream, которая устраняет необходимость разбрасывать вещи вместо непосредственного вызова strtol (чтов вашем случае, вероятно, должно быть strtoul для начала).

Ручное шестнадцатеричное преобразование

В своем последнем комментарии вы указываете, что использование iostream и stringstream для преобразованиямедленный. Вы можете попытаться немного оптимизировать, исключив поток строк и используя string::iterator, чтобы шагать по строке, вручную преобразовывая каждый символ и формируя каждый байт uint8_t по ходу (защита от окончательного клева или1/2 байта), например,

#include <iostream>
#include <iomanip>
#include <string>
#include <vector>

/* simple manual conversion of hexchar to value */
uint8_t c2hex (const char c)
{
    uint8_t u = 0;

    if ('0' <= c && c <= '9')
        u = c - '0';
    else if ('a' <= c && c <= 'f')
        u = c - 'W';
    else if ('A' <= c && c <= 'F')
        u = c - '7';
    else
        std::cerr << "error: invalid hex char '" << c << "'\n";

    return u;
}

int main (void) {

    std::string s ("0123456789abcdef");
    std::vector<uint8_t> msg;

    for (std::string::iterator n = s.begin(); n != s.end(); n += 2) {
        uint8_t u = c2hex (*n);             /* save high-nibble */
        if (n + 1 != s.end())               /* if low-nibble available */
            u = (u << 4) | c2hex (n[1]);    /* shift high left 4 & or */
        msg.push_back(u);                   /* store byte in msg */
    }

    std::cout << "string: " << s << "\nmsg:\n";
    for (auto& h : msg)
        std::cout << "\t" << std::setfill('0') << std::hex 
                    << std::setw(2) << (unsigned)h << '\n';
}

(вывод такой же, как указано выше)

Если вы можете гарантировать, что в вашей строке всегда будет четное количество символов (только байты)и без 1/2-байта в качестве последнего нечетного символа), вы можете дополнительно оптимизировать, удалив условное выражение и просто используя:

        uint8_t u = c2hex (n[1]) | (c2hex (*n) << 4);

Убедитесь, что вы компилируете с полной оптимизацией, например, -O3 (или -Ofast версия gcc> = 4.6) в gcc / clang и /Ox с VS.

Попробуйте и сравните производительность, вы можете дополнительно вывести различные версии в сборку и посмотреть, есть лидополнительные подсказки там.

0 голосов
/ 01 апреля 2019

Эта функция (спасибо Преобразование шестнадцатеричной строки в байтовый массив )

vector<uint8_t> HexToBytes(const string& hex) {
  vector<uint8_t> bytes;
  for (unsigned int i = 0; i < hex.length(); i += 2) {
    string byteString = hex.substr(i, 2);
    uint8_t byte = (uint8_t) strtol(byteString.c_str(), nullptr, 16);
    bytes.push_back(byte);
  }
  return bytes;
}

с помощью вышеуказанной функции мы получаем вектор байтов и вызываем метод data ()

Хочу поблагодарить сообщество, теперь все работает правильно.Спасибо за комментарии, я был уже в отчаянии, что я не мог сделать такую ​​простую вещь.Особая благодарность @ johnny-mopp

...