Bit operations in C

倖福魔咒の 提交于 2019-12-01 09:35:39
//turn on isUsed
data |= 1;
//turn off isUsed
data &= ~1;
//turn on notLast
data &= ~2;
//turn off notLast
data |= 2;

This is very simple:

/* Turn on bit 0 */
code = code | 1;

/* Turn off bit 0 */
code = code & ~1;

/* Turn on bit 1 */
code = code | 2;

/* Turn off bit 1 */
code = code & ~2;

See Bitwise operators in C, or Google for the appropriate terms. You can find this in any book or tutorial about C.

In general, counting the least significant bit as 0, to set bit N, you need to OR the original value with 1 << N.

Eg to set bit 1:

val |= (1 << 1);

To clear bit N, you need to AND the original value with the bit-wise inverse of 1 << N.

Eg to clear bit 1:

val &= ~(1 << 1);

This is begging for an interface, either with functions or macros, something like:

// Use unsigned ints (assuming that's your 32-bit type).

#define setLast(x)   (x) |=  2
#define clrLast(x)   (x) &= ~2
#define isLast(x)    ((x) &  2)

#define setUsed(x)   (x) |=  1
#define clrused(x)   (x) &= ~1
#define isUsed(x)    ((x) &  1)

You can also provide macros to extract the size portion and create the whole integer:

#define getSize(x) ((x) >> 4)
#define create (sz,last,used) \
    (((sz) & 0x0fffffff) << 4) | \
    (((last) & 1) << 1) | \
    (((used) & 1))

You'll find your code becomes a lot more readable if you provide the "functions" to do the work and give them sensible names like the above. Otherwise your code is peppered with bit manipulation instructions that are harder to understand.

Just keep in mind the normal rules for macros, things like not passing in things like x++ if your macros use it more than once (which isn't actually the case here). If you want to be ultra-safe, you can do them as functions.

Equivalent functions would be:

unsigned int setLast (unsigned int *x) { *x |=  2; return *x; }
unsigned int clrLast (unsigned int *x) { *x &= ~2; return *x; }
unsigned int isLast  (unsigned int  x) { return x & 2; }

unsigned int setUsed (unsigned int *x) { *x |=  1; return *x; }
unsigned int clrUsed (unsigned int *x) { *x &= ~1; return *x; }
unsigned int isUsed  (unsigned int  x) { return x & 1; }

unsigned int getSize (insigned int  x) { return x >> 4; }
unsigned int create  (unsigned int sz, unsigned int last, unsigned int used) {
    unsigned int ret =
        ((sz & 0x0fffffff) << 4) |
        ((last & 1) << 1) |
        ((used & 1));
    return ret;
}

Turn the flag on:

register |= (1<<LAST_BIT);

Turn the flag off:

register &= ~(1<<LAST_BIT);

Another way is to use union bit-fields:

union
{
  uint32_t value;
  struct
  {
    unit32_t body:28;
    unit32_t reserved:2;
    unit32_t last_bit:1;
    unit32_t used_bit:1;
  } fields;
} MyResister;

MyResister.fields.last_bit = 1;
MyResister.fields.used_bit = 0;

I would throw in a BIT(x) macro just to make the source code more clear:

#define BIT(n) (0x1U << (n))

Which would result in:

#define LAST_SET(x) ((x) |= BIT(1))
#define LAST_CLR(x)  ((x) &= ~BIT(1))

Also, as previously noted, always put the parameter in parenthesis.

(OT) Edit: Changed name of macro as I do not like having the verb first. First of all a function like getWhatever is for code where you can group the function in a class. In C, IMHO, you should put the "component" name first such as, timeGet() et c

(OT2) Also if it's a register macrofication like this is nice which would result in better portability:

#define MY_REG_RD() (MY_REG)
#define MY_REG_WR(x) (MY_REG = (x))
#define MY_REG_SET(x) (MY_REG |= (x))
#define MY_REG_CLR(x) (MY_REG &= ~(x))
#define MY_REG_DIS BIT(10)
#define MY_REG_EN BIT(4)

Then you could do:

MY_REG_SET(MY_REG_EN);
bool isBitOn( int mask , int i ){ // returns True if i-Th bit is On
    return mask & ( 1 << i ) ;
}

int BitOn( int mask , int i ){ // Turn On the i-Th bit of the value and then returns it
    return mask | ( 1 << i ) ;
}

int BitOff( int mask , int i ){ // Turn Off the i-Th bit of the value and then returns it
    return mask - ( 1 << i ) ;
}

int BitToggle( int mask , int i ){ // Toggle the i-Th bit of the value and then returns it
    return mask ^ ( 1 << i ) ;
}

void printbit(int n) { // print the Binary representation of a Integer Number
    for(int i = 31 ; i >=0 ; i-- )
        printf("%d", isBitOn(n,i) );
    printf("\n");
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!