Home > Software engineering >  convert std::array of bytes to hex std::string
convert std::array of bytes to hex std::string

Time:10-14

I'd like a way to take an arbitrary-size array of bytes and return a hex string. Specifically for logging packets sent over the net, but I use the equivalent function that takes a std::vector a lot. Something like this, probably a template?

std::string hex_str(const std::array<uint8_t,???> array);

I've searched but the solutions all say "treat it as a C-style array" and I am specifically asking whether there's a way not to do that. I assume the reason this isn't in every single C FAQ is that it's impossible and if so can someone outline why?

I already have these overloads and the second one can be used for std::array by decaying into a C-style array, so please don't tell me how to do that.

std::string hex_str(const std::vector<uint8_t> &data);
std::string hex_str(const uint8_t *data, const size_t size);

(edit: vector is a reference in my code)

CodePudding user response:

If you know the size of the std::array at compile time you can use a non type template parameter.

template<std::size_t N>
std::string hex_str( const std::array<std::uint8_t, N>& buffer )
{ /* Implementation */ }

int main( )
{   
    // Usage.
    std::array<std::uint8_t, 5> bytes = { 1, 2, 3, 4, 5 };
    const auto value{ hex_str( bytes ) };
}

Or you can just template the entire container (cut down on your overloads).

template<typename Container>
std::string hex_str( const Container& buffer ) 
{ /* Implementaion */ }

int main( )
{   
    // Usage.
    std::array<std::uint8_t, 5> bytes = { 1, 2, 3, 4, 5 };
    const auto value{ hex_str( bytes ) };
}

CodePudding user response:

You should consider writing the function to work with iterators, like standard algorithms do. Then you can use it with both std::vector and std::array inputs, eg:

template<typename Iter>
std::string hex_str(Iter begin, Iter end)
{
    std::ostringstream output;
    output << std::hex << std::setw(2) << std::setfill('0');
    while(begin != end)
        output << static_cast<unsigned>(*begin  );
    return output.str();
}

Online Demo

If you really want to avoid having to call begin()/end() on whatever container you pass in, you can define a helper to handle that for you, eg:

template<typename C>
std::string hex_str(const C &data) {
    return hex_str(data.begin(), data.end());
}

Online Demo

Or, if you really wanted to, you can just flatten this all down into a single function, eg:

template <typename C>
std::string hex_str(const C& data)
{
    std::ostringstream output;
    output << std::hex << std::setw(2) << std::setfill('0');
    for(const auto &elem : data)
        output << static_cast<unsigned>(elem);
    return output.str();
}

Online Demo

  •  Tags:  
  • c
  • Related