Convert from char string to uint8_t array?

I am reading a line from a file so that it is in the form of a char array. I need to tokenize a string and save each char array tag as the hexadecimal value of uint8_t in the array.

 char* starting = "001122AABBCC"; // ... uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC} 

How can I convert from starting to ending ? Thanks.

+6
source share
9 answers

Here is the complete work program. It is based on Rob I's solution, but fixed several problems that were tested to work.

 #include <string> #include <stdio.h> #include <stdlib.h> #include <vector> #include <iostream> const char* starting = "001122AABBCC"; int main() { std::string starting_str = starting; std::vector<unsigned char> ending; ending.reserve( starting_str.size()); for (int i = 0 ; i < starting_str.length() ; i+=2) { std::string pair = starting_str.substr( i, 2 ); ending.push_back(::strtol( pair.c_str(), 0, 16 )); } for(int i=0; i<ending.size(); ++i) { printf("0x%X\n", ending[i]); } } 
+2
source

strtoul will convert the text to any base that you select in bytes. You need to do a little work to slice the input string into separate digits or you can convert 32 or 64 bits at a time.

ps uint8_t[] ending = {0x00,0x11,0x22,0xAA,0xBB,0xCC}

Doesn’t mean anything, you do not store data in uint8 as "hex", you store bytes, it depends on how you (or your debugger) interpret binary data

+1
source

With C ++ 11, you can use std::stoi for this:

 std::vector<uint8_t> convert(const std::string& s) { if (s.size() % 2 != 0) { throw std::runtime_error("Bad size argument"); } std::vector<uint8_t> res; res.reserve(s.size() / 2); for (std::size_t i = 0, size = s.size(); i != size; i += 2) { std::size_t pos = 0; res.push_back(std::stoi(s.substr(i, 2), &pos, 16)); if (pos != 2) { throw std::runtime_error("bad character in argument"); } } return res; } 

Living example .

+1
source

I think that any canonical answer (wrt reward notes) will include some distinct phases in the solution:

  • Validation of input
    • Length check and
    • Checking Data Content
  • Element conversion
  • Output creation

Given the usefulness of such conversions, the solution should probably include some flexibility wrt types used and language required.

From the very beginning, given the date of the request for a β€œmore canonical answer” (around August 2014), the liberal use of C ++ 11 will be applied.

An annotated version of the code with types matching OP:

 std::vector<std::uint8_t> convert(std::string const& src) { // error check on the length if ((src.length() % 2) != 0) { throw std::invalid_argument("conversion error: input is not even length"); } auto ishex = [] (decltype(*src.begin()) c) { return std::isxdigit(c, std::locale()); }; // error check on the data contents if (!std::all_of(std::begin(src), std::end(src), ishex)) { throw std::invalid_argument("conversion error: input values are not not all xdigits"); } // allocate the result, initialised to 0 and size it to the correct length std::vector<std::uint8_t> result(src.length() / 2, 0); // run the actual conversion auto str = src.begin(); // track the location in the string std::for_each(result.begin(), result.end(), [&str](decltype(*result.begin())& element) { element = static_cast<std::uint8_t>(std::stoul(std::string(str, str + 2), nullptr, 16)); std::advance(str, 2); // next two elements }); return result; } 

The boilerplate version of the code adds flexibility;

 template <typename Int /*= std::uint8_t*/, typename Char = char, typename Traits = std::char_traits<Char>, typename Allocate = std::allocator<Char>, typename Locale = std::locale> std::vector<Int> basic_convert(std::basic_string<Char, Traits, Allocate> const& src, Locale locale = Locale()) { using string_type = std::basic_string<Char, Traits, Allocate>; auto ishex = [&locale] (decltype(*src.begin()) c) { return std::isxdigit(c, locale); }; if ((src.length() % 2) != 0) { throw std::invalid_argument("conversion error: input is not even length"); } if (!std::all_of(std::begin(src), std::end(src), ishex)) { throw std::invalid_argument("conversion error: input values are not not all xdigits"); } std::vector<Int> result(src.length() / 2, 0); auto str = std::begin(src); std::for_each(std::begin(result), std::end(result), [&str](decltype(*std::begin(result))& element) { element = static_cast<Int>(std::stoul(string_type(str, str + 2), nullptr, 16)); std::advance(str, 2); }); return result; } 

Then the convert() function can be based on basic_convert() as follows:

 std::vector<std::uint8_t> convert(std::string const& src) { return basic_convert<std::uint8_t>(src, std::locale()); } 

Live sample .

+1
source

uint8_t is usually no more than an unsigned typedef char. If you are reading characters from a file, you should be able to read them into an unsigned char array as easily as a signed char array, and an unsigned char array is a uint8_t array.

0
source

I would try something like this:

 std::string starting_str = starting; uint8_t[] ending = new uint8_t[starting_str.length()/2]; for (int i = 0 ; i < starting_str.length() ; i+=2) { std::string pair = starting_str.substr( i, i+2 ); ending[i/2] = ::strtol( pair.c_str(), 0, 16 ); } 

Not tested it, but it looks good to me ...

0
source

You can add your own conversion from the set char {'0', '1', ... 'E', 'F'} to uint8_t:

 uint8_t ctoa(char c) { if( c >= '0' && c <= '9' ) return c - '0'; else if( c >= 'a' && c <= 'f' ) return 0xA + c - 'a'; else if( c >= 'A' && c <= 'F' ) return 0xA + c - 'A'; else return 0; } 

Then it will be easy to convert the string to an array:

 uint32_t endingSize = strlen(starting)/2; uint8_t* ending = new uint8_t[endingSize]; for( uint32_t i=0; i<endingSize; i++ ) { ending[i] = ( ctoa( starting[i*2] ) << 4 ) + ctoa( starting[i*2+1] ); } 
0
source

This simple solution should work for your problem.

 char* starting = "001122AABBCC"; uint8_t ending[12]; // This algo will work for any size of starting // However, you have to make sure that the ending have enough space. int i=0; while (i<strlen(starting)) { // convert the character to string char str[2] = "\0"; str[0] = starting[i]; // convert string to int base 16 ending[i]= (uint8_t)atoi(str,16); i++; } 
0
source
 uint8_t* ending = static_cast<uint8_t*>(starting); 
-1
source

Source: https://habr.com/ru/post/921428/


All Articles