5

I have something like the following, and after populating it with a arbitrary number of bits, I need to get the bytes to write out to a file. I don't see a way to do this and it seems useful, so I must be missing something. Any idea's?

std::vector<bool> a;

a.push_back(true);
a.push_back(false);
a.push_back(false);
a.push_back(true);

a.push_back(false);
a.push_back(true);
a.push_back(true);
a.push_back(false);
James
  • 148
  • 1
  • 7
  • 1
    To be sure: do you want the bytes containing the packed bits? I mean, in the example you gave, would the output be just one byte with the value 0x96? And one more thing: what is the desired endianess? – Fabio Ceconello Feb 16 '09 at 01:16
  • Is there any point to writing an output function if there's no possible way to read it back? Even if you do read back just one raw byte==0x00, you still don't know how big the vector was. – MSalters Feb 16 '09 at 09:37
  • I do want the packed bytes and each bit vector would have a variable number of bits. – James Feb 16 '09 at 13:50

9 Answers9

8

std::vector <bool> does not actually contain bools (i.e.bytes) , it contains bits! This is mostly a missfeature and you are advised to use std::deque <bool>, which doesn't have this "feature" instead.

And if you want the storage to be contiguous, use std::vector <char>.

  • 1
    Yay for template specializations! – JaredPar Feb 15 '09 at 21:11
  • hor bitset. he definitely wants bitset and its op>> and op<< for streams, or for dynamic ones http://www.boost.org/doc/libs/1_38_0/libs/dynamic_bitset/dynamic_bitset.html – Johannes Schaub - litb Feb 15 '09 at 23:31
  • 1
    The committee had the guts to drop `export` for C++0B. Too bad they didn't drop `vector`. – David Thornley Apr 08 '10 at 20:24
  • 1
    I'd not say it's a misfeature, this implementation decreases the memory storage cost by 8 times as the single byte may store up to 8 bits. There's also no problem if you want to access the continuous buffer as you can always use vector as you've suggested. – vnd Sep 23 '15 at 13:18
2

Try this

void WriteOut(fstream& stream, const vector<bool>& data) {
  for (vector<bool>::const_iterator it = data.begin(); it != data.end(); it++) {
    stream << *it;
  }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

I can't remember if an std::vector<bool> is required to be packed, most probably it's not. If it was you could access its ::data() member to have access to the raw bytes.

baol
  • 4,362
  • 34
  • 44
1

A bool is normally a byte - you can simply iterate over the vector using the vector::iterator, and access each value that way.

std::vector<bool> a;

a.push_back(true);
a.push_back(false);

for(std::vector<bool>::iterator iter = a.begin(); iter != a.end(); ++iter)
{
    std::cout << *iter << std::endl;
}

Will iterate over each bool, and print it out to the command line. Printing to a file is relatively straightforward.

jasedit
  • 662
  • 4
  • 10
  • 1
    A bool is not normally a byte. On many systems it is the CPU word size, e.g. 32 bits, because that is faster than manipulating bytes. – Brian Neal Feb 15 '09 at 21:59
  • 4
    And a `vector` is not a `vector<>` of `bool`, in arguably the worst misfeature of the C++ Standard. – David Thornley Apr 08 '10 at 20:25
1

Do something like this

std::vector<bool> a;
a.push_back(true);
a.push_back(false);
//...
for (auto it = a.begin(); it != a.end();) // see 0x for meaning of auto
{
    unsigned b = 0;
    for (int i = 0; i < 8*sizeof(b); ++i)
    {
        b |= (*it & 1) << (8*sizeof(b) - 1 - i);
        ++it;
    }
    // flush 'b'
}

So, what you end up doing is that you group chunks of bits together, here I've chosen to group bits into native integers (which is optimal for the target platform). I don't check the indexes here but that's something you'll have to do. What I would do is that I would check how many full chunks I could extract first, do that and then handle any remainder.

Also, note that I'm filling in bits from left to right (assuming the target architecture is little-endian) this means filling in the msb first.

If your doing bit manipulation and stuff like that, figure out a packing scheme for you bits and let that be your data structure. std::bit_vector, std::vector or ::dequeue doesn't really matter. Pack your bits cleverly into the target platform's native integer type, that will give the best kind of performance.

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • Indeed. However, this is of course inefficient so if performance matters, you should make your own container (providing access to raw data) instead –  Feb 15 '09 at 21:20
  • @John: Question to the responder http://stackoverflow.com/questions/578791/shift-operations, as well as rest of you... –  Feb 23 '09 at 18:44
1

Why don't you use the STL bitset instead? It has specific methods to convert the bitset values to it equivalent long value or string representation:

http://www.cppreference.com/wiki/stl/bitset/start

igece
  • 341
  • 1
  • 3
  • 12
0

Actually you could do this:

copy(yourvector.begin(), yourvector.end(), std::ostreambuf_iterator<char>(outputstream));
0

After looking at the suggested solutions above, I ended up just writing a fully working function.

  // Count number of bytes needed to contain the bits
  // and then copy 8 bit block as bytes.

  void writeAsBytes(const vector<bool> & inBits, vector<uint8_t> & outBytes) {
    int bitOffset = 0;
    const int maxBitOffset = (int) inBits.size();

    const bool emitMSB = true;

    int numBytes = (int)inBits.size() / 8;
    if ((inBits.size() % 8) != 0) {
      numBytes += 1;
    }

    for (int bytei = 0; bytei < numBytes; bytei++) {
      // Consume next 8 bits

      uint8_t byteVal = 0;

      for (int biti = 0; biti < 8; biti++ ) {
        if (bitOffset >= maxBitOffset) {
          break;
        }

        bool bit = inBits[bitOffset++];

        // Flush 8 bits to backing array of bytes.
        // Note that bits can be written as either
        // LSB first (reversed) or MSB first (not reversed).

        if (emitMSB) {
          byteVal |= (bit << (7 - biti));
        } else {
          byteVal |= (bit << biti);
        }
      }

      outBytes.push_back(byteVal);
    }
  }
MoDJ
  • 4,309
  • 2
  • 30
  • 65
0

First, you want to use bit_vector instead of vector.

Second, there is no way to do exactly what you want using bit_vector or vector. They are designed to be collections and their underlying format is hidden from you (thus it might decide to store each bool as an individual byte rather than packed as 8 bits per byte.

SoapBox
  • 20,457
  • 3
  • 51
  • 87