1

I'm sending a fixed length byte stream over a serial port to another computer and I'd like to try and convert the byte stream to a vector of floating point numbers.

My stream has a delimiter stop and I'm using this serial library.

My current implementation involves the following:

I read a string

 std::string data_string;
 ser.readline(data_string, 2052, "stop");

Check if the string ends with the delimiter

 if(boost::algorithm::ends_with(stop_string, "stop"))
    {                
       if(data_string.length() == 2052)

Then convert the string to a vector

   std::vector<unsigned char>bytes(stop_string.begin(), stop_string.end());

I then use a for loop and memcpy to convert bytes to an array of floating point numbers.

     unsigned char temp_buffer[4];
     float float_values[513] = { 0 };
     int j = 0;
     for(size_t i = 4; i < 2052; i+=4)
          {
              temp_buffer[0] = bytes[i - 4];
              temp_buffer[1] = bytes[i - 3];
              temp_buffer[2] = bytes[i - 2];
              temp_buffer[3] = bytes[i - 1];
              memcpy(&float_values[j], temp_buffer, sizeof(float));
              j++;
           }

But this method looks cumbersome and I'd like to avoid the for loop. Is there a way to:

  • convert the bytes vector to a vector of floating point numbers instead?

  • avoid the for loop?

MaskedAfrican
  • 196
  • 2
  • 12
  • If you find this answer useful, please consider "accepting" it (by clicking the tick (✓) next to it) to indicate you've found a working solution and also so that others may more easily find it in the future. – ppetraki Apr 19 '19 at 18:38

2 Answers2

2

The array of floats and the vector of unsigned chars are the same size in bytes. You can just memcpy directly into the array of floats from your buffer.

It's not as if your bytes are swapped or anything. You just want to interpret 4 consecutive bytes as a float.

That also eliminates the loop

EDIT UPDATE:

If you're using C++11 or higher, you can rely on the fact that std::string's internal buffer is stored contiguously and just copy directly from that. There's no need for the temporary bytes buffer, which saves you a considerable amount of memory (half a page).

Example:

// copy directly from string
float float_values[data_string.size()/sizeof(float)]; // 513
std::memcpy(float_values, data_string.data(), data_string.size());
ppetraki
  • 428
  • 4
  • 11
1

Since you tagged as general C++, I'll use some of the cool new features C++20 has introduced :)

#include <algorithm>
#include <cstddef>
#include <span>
#include <vector>

std::vector<float> ToFloats(const std::vector<std::byte>& bytes) {
    std::vector<float> floats(bytes.size() / sizeof(float), 0.0f);
    std::copy_n(bytes.begin(), floats.size() * sizeof(float),
                std::as_writable_bytes(std::span(floats)).begin());
    return floats;
}

Live Example (std::byte, std::span, std:: as_writable_bytes)

Brian Rodriguez
  • 4,250
  • 1
  • 16
  • 37