Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

How Do I...

Name: Anonymous 2008-08-29 13:31

...access individual bits in a byte in C++?

Name: Anonymous 2008-08-29 16:32

I'd use std::bitset, it's a robust class for handling sets of bits.

#include <iostream>
#include <sstream>
#include <iomanip>
#include <bitset>
#include <iostream>
#include <numeric>
#include <locale>

namespace bit_twiddling {
    namespace detail {
        template<class T>
        class binary_num_put_facet : public std::num_put<T> {
        public:
            iter_type do_do_put(iter_type itr, std::ios_base&, char_type fill, unsigned long val) const {
                //Gets the most significant bit for an unsigned long.
                unsigned long bit = 1 << sizeof(unsigned long) * CHAR_BIT - 1;
                while(bit) {
                    *itr++ = val & bit ? '1': '0';
                    bit >>= 1;
                }
                return itr;
            }

            iter_type do_put(iter_type itr, std::ios_base& io, char_type fill, bool v) const {
                return do_do_put(itr, io, fill, static_cast<unsigned long>(v));
            }

            iter_type do_put(iter_type itr, std::ios_base& io, char_type fill, long v) const {
                return do_do_put(itr, io, fill, static_cast<unsigned long>(v));
            }

            iter_type do_put(iter_type itr, std::ios_base& io, char_type fill, unsigned long v) const {
                return do_do_put(itr, io, fill, static_cast<unsigned long>(v));
            }

            iter_type do_put(iter_type itr, std::ios_base& io, char_type fill, long double v) const {
                return do_do_put(itr, io, fill, static_cast<unsigned long>(v));
            }

            iter_type do_put(iter_type itr, std::ios_base& io, char_type fill, const void* v) const {
                return do_do_put(itr, io, fill, reinterpret_cast<unsigned long>(v));
            }
        };

        template<class T>
        class binary_num_get_facet : public std::num_get<T> {
        public:
            template<class T>
            iter_type do_do_get(iter_type in, iter_type end, std::ios_base&, std::ios_base::iostate& err, T& val) const {
                T current = T();

                //Should start with a 1 or 0. I assume it skips whitespace for us?
                if(*in != '0' && *in != '1') {
                    //val is left unchanged.
                    err = std::ios_base::failbit;
                    return in;
                }

                while(in != end) {
                    if(*in == '1') {
                        current = (current << 1) | 1;
                    } else if(*in == '0') {
                        current <<= 1;
                    } else {
                        break;
                    }
                    ++in;
                }

                err = std::ios_base::goodbit;
                val = current;
                return in;
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, long& v) const {
                return do_do_get(in, end, io, err, v);
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, unsigned short& v) const {
                return do_do_get(in, end, io, err, v);
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, unsigned int& v) const {
                return do_do_get(in, end, io, err, v);
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, unsigned long& v) const {
                return do_do_get(in, end, io, err, v);
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, float& v) const {
                err = std::ios_base::failbit;
                return in;
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, double& v) const {
                err = std::ios_base::failbit;
                return in;
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, long double& v) const {
                err = std::ios_base::failbit;
                return in;
            }

            iter_type do_get(iter_type in, iter_type end, std::ios_base& io, std::ios_base::iostate& err, void*& v) const {
                err = std::ios_base::failbit;
                return in;
            }
        };
    }

    //TODO: add template constraints or static assertion that IntegerT really is an integer.
    template<class IntegerT>
    bool get_bit(IntegerT value, int bit) {
        std::ostringstream os;

        //BEWARE! Allocating this on the stack would have caused heap corruption.
        //std::locale::facet uses a reference counting mechanism, and will be deleted
        //when the time comes. If it is allocated on the stack, it will be deleted twice.
        std::locale bnp_locale(os.getloc(), new detail::binary_num_put_facet<char>);
        os.imbue(bnp_locale);
        os << value;

        //Now, at long last, set the Nth bit in the bitset.
        std::string str = os.str();
        std::bitset<CHAR_BIT * sizeof IntegerT> bs(str);
        return bs.test(bit);
    }

    template<class IntegerT>
    IntegerT set_bit(IntegerT value, int bit, bool set) {

        std::ostringstream os;
        std::locale bnp_locale(os.getloc(), new detail::binary_num_put_facet<char>); //Beware - see get_bit
        os.imbue(bnp_locale);
        os << value;

        //Now, at long last, set the Nth bit in the bitset.
        std::string str = os.str();
        std::bitset<CHAR_BIT * sizeof IntegerT> bs(str);
        bs.set(bit, set);

        //Read the number back from the stream using a locale with the binary num_get facet added.
        std::istringstream is(bs.to_string('0'));
        std::locale bng_locale(os.getloc(), new detail::binary_num_get_facet<char>);
        is.imbue(bng_locale);
        is >> value;
        return value;
    }
}

int main() {
    long x = 32;
    endl(std::cout << "x is " << x);
    endl(std::cout << "7th bit of x is " << bit_twiddling::get_bit(x, 7));
    endl(std::cout << "Setting 7th bit in x, please wait...");
    x = bit_twiddling::set_bit(x, 7, true);
    endl(std::cout << "x is " << x);
    endl(std::cout << "7th bit of x is " << bit_twiddling::get_bit(x, 7));
    endl(std::cout << "Unsetting 7th bit in x, please wait...");
    x = bit_twiddling::set_bit(x, 7, false);
    endl(std::cout << "x is " << x);
    endl(std::cout << "Done.");

    std::cin.get();
}


SEPPLES QUALITY!

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List