-5

I'm trying to write a macro to check whether a specific range of bits is on or off, the user is suppose to enter the number, the beginning bit and the end bit. So if the user enters the decimal number 31, 2, 4, it has to check if all the bits from 2 through 4 are 1, if they are all 1, then it returns true. If they aren't all 1, then it returns false. In this case, they are all 1, so it would return true

#define ALLON(X, S, E) //(MACRO HERE)

How do I make a macro to do this?

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
Dac Asf
  • 67
  • 1
  • 7
  • 1
    possible duplicate of [How do you set, clear and toggle a single bit in C/C++?](http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c-c) – 2501 Oct 24 '14 at 22:20
  • 1
    @DoxyLover: It doesn't require iteration over a range. – Crowman Oct 24 '14 at 22:22
  • 1
    @2501 - disagree that this is a duplicate of that. Your linked question talks about single bits. the OP wants a range of bits, specified by start and end bit numbers. – DoxyLover Oct 24 '14 at 22:23
  • @PaulGriffiths - how else do you propose to convert (2,4) into `00011100`? – DoxyLover Oct 24 '14 at 22:24
  • 1
    @DoxyLover: With bit shift operators. – Crowman Oct 24 '14 at 22:26
  • @PaulGriffiths - agreed. I just figured it out. Quite nice. – DoxyLover Oct 24 '14 at 22:28
  • 1
    So uhh, can anyone here help me? – Dac Asf Oct 24 '14 at 22:30
  • @DacAsf: You could help yourself quite a lot by putting a bit more effort into your question. – Crowman Oct 24 '14 at 22:31
  • I have to run. If @PaulGriffiths hasn't answered, I'll try later. – DoxyLover Oct 24 '14 at 22:31
  • @PaulGriffiths Im not too sure what else I should add. I just need a bitwise function that checks if the bits in a range of values are all 1 using the variables x, s, e – Dac Asf Oct 24 '14 at 22:34
  • Ok well I tried left shifting from the starting bit and right shifting from the ending bit and then xor the range with a string of 0's. It works for the number 31, but not for 30. – Dac Asf Oct 24 '14 at 22:48

2 Answers2

1

You can do this with some elementary bit shifting and bitwise logical operations. This'll do it:

#include <stdio.h>

#define ALLON(X,S,E) ((X & (~((~0U << E) | ~(~0U << (S - 1))))) == (~((~0U << E) | ~(~0U << (S - 1)))))

/*
    Or, simplifying with two macros...

    #define ALLMASK(S,E) (~((~0U << E) | ~(~0U << (S - 1))))
    #define ALLON(X,S,E) ((X & ALLMASK(S,E)) == ALLMASK(S,E))
*/

char * convert_to_8bit(char * buffer, const unsigned int n)
{
    size_t k = 0;
    for ( unsigned int i = 128; i > 0; i >>= 1 ) {
        if ( n & i ) {
            buffer[k++] = '1';
        }
        else {
            buffer[k++] = '0';
        }
    }
    return buffer;
}

int main(void)
{
    char buffer[9] = {0};

    printf("1 in binary is %s\n", convert_to_8bit(buffer, 1));
    printf("ALLON(1, 2, 4) is %s\n", ALLON(1, 2, 4) ? "true" : "false");
    printf("ALLON(1, 1, 1) is %s\n", ALLON(1, 1, 1) ? "true" : "false");

    printf("30 in binary is %s\n", convert_to_8bit(buffer, 30));
    printf("ALLON(30, 2, 4) is %s\n", ALLON(30, 2, 4) ? "true" : "false");
    printf("ALLON(30, 1, 1) is %s\n", ALLON(30, 1, 1) ? "true" : "false");
    printf("ALLON(30, 5, 5) is %s\n", ALLON(30, 5, 5) ? "true" : "false");
    printf("ALLON(30, 5, 6) is %s\n", ALLON(30, 5, 6) ? "true" : "false");

    return 0;
}

Output:

paul@horus:~/src/sandbox$ ./bs
1 in binary is 00000001
ALLON(1, 2, 4) is false
ALLON(1, 1, 1) is true
30 in binary is 00011110
ALLON(30, 2, 4) is true
ALLON(30, 1, 1) is false
ALLON(30, 5, 5) is true
ALLON(30, 5, 6) is false
paul@horus:~/src/sandbox$ 

Briefly, suppose we're doing ALLON(31, 2, 4):

  1. ~0U << E takes 11111111 and left shifts it 4, so you get 11110000
  2. ~0U << (S - 1) takes 11111111 and left shifts it 1, so you get 11111110
  3. ~(~0U << (S - 1)) negates what you just did, giving you 00000001
  4. ORing the two gives you 11110001, where bits 2, 3 and 4 are 0.
  5. Negating that gives you 00001110 where the bits you're interested in are 1.
  6. If ANDing that with X equals the mask itself, then all your bits are set.

There's probably a shorter way to do it, but this way is at least easy to understand.

Crowman
  • 25,242
  • 5
  • 48
  • 56
0

Something like this:

#define GET_MASK(S, E)       (((1UL << (E - S + 1)) - 1) << S)

#define ALLOCN(X, S, E)      (((GET_MASK(S,E) & X) == GET_MASK(S,E)) ? 1 : 0)

Here, GET_MASK gives you the mask corresponding to the bits which you wish to check. ALLOCN returns 1 if exactly all those bits are set in X else 0. (This is assuming bit numbering starts from 0)

IMPORTANT: There is no check for overflow here.

Hope this helps.

Furquan
  • 676
  • 3
  • 5
  • If you just bitwise AND `X` with the mask, it'll evaluate to true if *any* of the bits are set, not only when *all* of them are set. Also, this algorithm just doesn't work right. Try it with a few numbers and you'll see. – Crowman Oct 24 '14 at 23:02
  • Good catch Paul! You are right. We will have to check if mask & X gives you mask exactly! I updated the answer accordingly – Furquan Oct 24 '14 at 23:15