Question

I have a string of 1s and 0s that i padded with enough 0s to make its length exactly divisible by 8. My goal is to convert this string to a number of bytes and order it in such a way that the first character i read is the least siginificant bit, then the next on is the next least siginificant, etc until i have read 8 bits, save that as a byte and the continue reading the string saving the next bit as as the least siginificant bit of the second byte.

As an example the string "0101101101010010" is length 16 so it will be converted into two bytes. The first byte should be "11011010" and the second byte should be "01001010".

I am unsure how to do this because it is not as simple as reversing the string (i need to maintain the order of these bytes).

Any help is appreciated, thanks!

Était-ce utile?

La solution

You could iterate backwards through the string, but reversing it like you suggest might be easier. From there, you can just build the bytes one at a time. A nested for loop would work nicely:

unsigned char bytes[8]; // Make sure this is zeroed
for (int i=0, j=0; i<str.length(); j++) {
  for (int k=0; k<8; k++, i++) {
    bytes[j] >>= 1;
    if (str[i] == '1') bytes[j] |= 0x80;
  }
}

i is the current string index, j is the current byte array index, and k counts how many bits we've set in the current byte. We set the bit if the current character is 1, otherwise we leave it unset. It's important that the byte array is unsigned since we're using a right-shift.

Autres conseils

You can get the number of bytes using the string::size / 8.

Then, it is just a matter of reversing the sub-strings. You can do something like that:

for(int i=0; i<number_of_bytes; i++)
{
  std::string temp_substr = original.substr(i*8,8);
  std::reversed = string(temp_substr.rbegin(),temp_substr.rend()) // using reverse iterators

  //now you can save that "byte" represented in the "reversed" string, for example using memcpy
}

Depends whether you want to expose it as a general purpose function or encapsulate it in a class which will ensure you have all the right constraints applied, such as all the characters being either 0 or 1.

#include <cstdint>
#include <string>
#include <algorithm>
#include <iostream>

static const size_t BitsPerByte = 8;

// Suitable for a member function where you know all the constraints are met.
uint64_t crudeBinaryDecode(const std::string& src)
{
    uint64_t value = 0;
    const size_t numBits = src.size();
    for (size_t bitNo = 0; bitNo < numBits; ++bitNo)
        value |= uint64_t(src[bitNo] - '0') << bitNo;
    return value;
}

uint64_t clearerBinaryDecode(const std::string& src)
{
    static const size_t BitsPerByte = 8;
    if ((src.size() & (BitsPerByte - 1)) != 0)
        throw std::invalid_argument("binary value must be padded to a byte size");
    uint64_t value = 0;
    const size_t numBits = std::min(src.size(), sizeof(value) * BitsPerByte);
    for (size_t bitNo = 0; bitNo < numBits; ++bitNo) {
        uint64_t bitValue = (src[bitNo] == '0') ? 0ULL : 1ULL;
        value |= bitValue << bitNo;
    }
    return value;
}

int main()
{
    std::string dead("1011" "0101" "0111" "1011");
    std::string beef("1111" "0111" "0111" "1101");
    std::string bse ("1111" "0111" "0111" "1101" "1011" "0101" "0111" "1011" "1111" "0111" "0111" "1101" "1011" "0111" "0111" "1111");

    std::cout << std::hex;

    std::cout << "'dead' is: " << crudeBinaryDecode(dead) << std::endl;
    std::cout << "'beef' is: " << clearerBinaryDecode(beef) << std::endl;

    std::cout << "'bse'  is: " << crudeBinaryDecode(bse) << std::endl;

    return 0;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top