views:

640

answers:

3

Hi

I'd like to check if a binary number has a '0' or a '1' at a specific position.

example:

if the binary number is: 101000100

  • checking at position zero (that is at the rightmost '0') should result in '0'.
  • checking at position 2 should result in '1'.
  • checking at position 3 should result in '0'.
  • checking at position 6 should result in '1'.

    etc...

I'm coding in C, so obviously I could use sprintf / scanf and the likes, but I guess there must be something better (read: more time efficient / easier)!

What would be a good mechanism to do this?

+25  A: 

This will filter out the bit you're looking for:

number & (1 << position)

If you really need a 1 or 0 response, you can use this to make it a boolean value:

!!(number & (1 << position))

Or even better (thanks Vadim K.):

(number >> position) & 1
Wim
Making it boolean does not make it 0 or 1. In C++ it makes it true/false in C the actual value that represents true is (!FALSE) which is not nesacerly 1.
Martin York
Wim
Martin York: The result of the unary `!` operator is either 0 or 1.
caf
ysth
+7  A: 

Warning: This code is not Standards-compliant. Bjarne Stroustrup says, and he oughta' know, that, "Obviously, it's illegal to write one member and then read another..." Nevertheless I leave this code up for educational purposes...

Here's an alternative that is useful when, say, reading a proprietary binary protocol off of a socket:

#include <cstdlib>


union Value
{
    struct
    {
        unsigned char a_ : 1;
        unsigned char b_ : 1;
        unsigned char c_ : 1;
        unsigned char d_ : 1;
        unsigned char e_ : 1;
        unsigned char f_ : 1;
        unsigned char g_ : 1;
        unsigned char h_ : 1;
    } bits_;
    unsigned char charVal_;
};


int main()
{

    unsigned char someValue = static_cast<unsigned char>(0x42);
    Value val;
    val.charVal_ = someValue;

    bool isBitDSet = val.bits_.d_;

    return 0;
}
John Dibling
+1 for having named bits :)
Autopulated
you also have to be careful about the byte order..
Amro
It's undefined behavior to access a union in this manner.
avakar
@avakar: Please elaborate.
John Dibling
The standard only guarantees, roughly put, that the last union-member written to is accessible.
Georg Fritzsche
You write to an union member, then read from another one. This is undefined behavior per 9.5/1: "*In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of non-static data members can be stored in a union at any time.*". In this case, you cannot store the value of `charVal_` and the value of `bits_` in the union at the same time. What you *can* do is write to `charVal_`, read back what you wrote there, then write to `bits_`, and read what you wrote in `bits_`.
Stefan Monov
Fair enough, good to know. That said, it still works for me. :)
John Dibling
This is a hack. It is a hack even within a single given platform. On top of that, it is not portable between platforms. I see absolutely no reason why anyone would use something like that instead of the obvious shift-and-test solution.
AndreyT
My reading of the standard is that when a union's member is written to, its other members take on an "implementation-defined value." It's not undefined behavior as far as I can determine.
greyfade
@AndreyT - Because it is potentially faster. See my next comment regarding Standards compliance...
John Dibling
Regarding clause 9.5/1: As quoted above, only one member of a union can be active at a time. But the Standard goes on to clarify a bit: "[...]that is, the value of at most one of the datamembers can be stored in a union at any time." Seems to me this is simply defining the basic character of a union; nameley, that each member occupies the same space in memory. The Standard does not say that once you have assigned a value to one member it cannot be accessed through another member. (continued...)
John Dibling
John Dibling
Well, I take it all back. On Stroustrup's site (http://www2.research.att.com/~bs/C++0xFAQ.html#unions) he says explicitly "Obviously, it's illegal to write one member and then read another but people do that nevertheless (usually by mistake)."
John Dibling
I was certain that the standard made this undefined, but then I failed to find the relevant quote, so I'm not really sure right now. C99 makes the behavior implementation-defined. Note that accessing an object through an lvalue of type different than object's dynamic type is, with some exceptions, undefined (your code happens to be that exception though). In any case, the ordering of bitfields is implementation-defined, so an objective reason to avoid this misuse of unions remains.
avakar
The fundamental portion that makes it illegal in C standard (C89/90 and C99) is 6.5/7. It clearly states that memory occupied by object of one type cannot be accessed as object of another type (with some exceptions). In other words, *memory reinterpretation* is [almost] always illegal. Whether it is done through union, cast or by any other way is completely unimportant.
AndreyT
Indeed, but John's code happens to fall into those exceptions ("An object shall have its stored value accessed only by an lvalue expression that has one of the following types: [...], a character type"), i.e. the behavior is only implementation-defined in this particular case (per 6.5.2.3/5 in C99). For C++, the "character type" exception applies too, but 9.5/1 (the equivalent of C99's 6.5.2.3/5) doesn't make the behavior implementation-defined.
avakar
+22  A: 

This expression evaluates to the value of the bit you're looking for, either 0 or 1:

(number >> position) & 1
Vadim K.