Name: Anonymous 2008-08-29 13:31
...access individual bits in a byte in C++?
binary_cast
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!
int16 (at least 16 bits, whatever works for this platform) vs int16! (exactly 16 bits, mask off if register size is larger). I think there's a language or two that can do this nowadays.
int16' already exists as short/int and as int_least16_t/int_fast16_t with <stdint.h>.<limits.h>.int9_t wouldn't work anyway on most platforms, and if you're worried about portability you'd probably be better to use something like int_least16_t or int_least32_t instead of int_least18_t.
int18 you would normally just use a long (are those extra bits really gonna hurt you?), but if you insist on having the smallest sufficient type you can use the preprocessor to pick the right one.#include <limits.h>
#include <stdio.h>
typedef
#if SCHAR_MAX >= 131071
signed char
#elif SHORT_MAX >= 131071
short
#elif INT_MAX >= 131071
int
#else
long // We know it's big enough
#endif
int18;
int main(void)
{
printf("%d\n", CHAR_BIT * sizeof(int18));
}Give me the n-th bit, please, Dr. Sussman!