24

Say I have a byte like this 1010XXXX where the X values could be anything. I want to set the lower four bits to a specific pattern, say 1100, while leaving the upper four bits unaffected. How would I do this the fastest in C?

PICyourBrain
  • 9,976
  • 26
  • 91
  • 136
  • Related: *[What are bitwise shift (bit-shift) operators and how do they work?](https://stackoverflow.com/questions/141525/what-are-bitwise-shift-bit-shift-operators-and-how-do-they-work)* – Peter Mortensen Aug 14 '23 at 03:18

4 Answers4

59

In general:

value = (value & ~mask) | (newvalue & mask);

mask is a value with all bits to be changed (and only them) set to 1 - it would be 0xf in your case. newvalue is a value that contains the new state of those bits - all other bits are essentially ignored.

This will work for all types for which bitwise operators are supported.

thkala
  • 84,049
  • 23
  • 157
  • 201
  • 2
    Can you please give a specific example? Suppose I have: n = 1024. I want to change bits from position 3 to 7 (inclusive, starting from 0 with the least significant bit) to k = 19. The result should be: 1176. How can I achieve it? Thank you. – dh16 Jun 23 '17 at 21:41
  • 2
    Having just had to figure this out myself, I've come up with the following macros to generalise the problem. (No idea why code formatting isn't working, sorry) ``` #define MASK(L,P) (~(0xffffffff << (L)) << (P)) #define GET_VAL(BF,L,P) (((BF) & MASK(L,P)) >> P) #define SET_VAL(BF,L,P,V) ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) ) int main(int argc, char ** argv) { uint32_t bf = 1024; printf("Bitfield before : %d , 0x%08x\n", bf, bf); SET_VAL(bf,5,3,19); printf("Bitfield after : %d , 0x%08x\n", bf, bf); return 0; } ``` – Micha Jan 25 '21 at 06:04
20

You can set all those bits to 0 by bitwise-anding with the 4 bits set to 0 and all other set to 1 (This is the complement of the 4 bits set to 1). You can then bitwise-or in the bits as you would normally.

ie

 val &= ~0xf; // Clear lower 4 bits. Note: ~0xf == 0xfffffff0
 val |= lower4Bits & 0xf; // Worth anding with the 4 bits set to 1 to make sure no
                          // other bits are set.
Goz
  • 61,365
  • 24
  • 124
  • 204
  • 2
    why ~0xf is equal to 0x0000000f (four bytes), why not 3 bytes or 5 bytes? Did the compiler decide the length 4 based on the sizeof val which to be ANDED with? – doc_id Jan 23 '21 at 06:59
  • 1
    @doc_id: I am assuming that val is a 32-bit integer. It could be 16-bit or 64-bit but unlikely to be 24 or 40 bit as they are not standard integer types ... – Goz Jan 26 '21 at 11:53
3

To further generalise the answers given, here are a couple of macros (for 32-bit values; adjust for different bitfield lengths).

#include <stdio.h>
#include <stdint.h>

#define MASK(L,P)            (~(0xffffffff << (L)) << (P))

#define GET_VAL(BF,L,P)      (((BF) & MASK(L,P)) >> P)
#define SET_VAL(BF,L,P,V)    ( (BF) = ((BF) & ~MASK(L,P)) | (((V) << (P)) & MASK(L,P)) )

int main(int argc, char ** argv)
{
    uint32_t bf = 1024;

    printf("Bitfield before : %d , 0x%08x\n", bf, bf);

    
    printf("Mask(5,3): %d , 0x%08x\n", MASK(5,3), MASK(5,3));


    SET_VAL(bf,5,3,19);
    printf("Bitfield after : %d , 0x%08x\n", bf, bf);

    return 0;
}

As an aside, it's ridiculous that the C bitfield is completely useless. It's the perfect syntactic sugar for this requirement but due to leaving it up to each compiler to implement as it sees fit, it's useless for any real-world usage.

Micha
  • 151
  • 3
1

Use the bitwise OR operator, |, when you want to change the bit of a byte from 0 to 1.

Use the bitwise AND operator, &, when you want to change the bit of a byte from 1 to 0.

Example

#include <stdio.h>

int byte;
int chb;

int main() {
    // Change bit 2 of byte from 0 to 1
    byte = 0b10101010;
    chb = 0b00000100;        // 0 to 1 change byte
    printf("%d\n", byte);    // Display current status of byte

    byte = byte | chb;       // Perform 0 to 1 single bit changing operation
    printf("%d\n", byte);

    // Change bit 2 of byte back from 1 to 0
    chb = 0b11111011;        // 1 to 0 change byte

    byte = byte & chb;       // Perform 1 to 0 single bit changing operation
    printf("%d\n", byte);
}

Maybe there are better ways; I don’t know. This will help you for now.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tuncel3
  • 21
  • 5