Bit Operations using Macros

Code

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

//macros
#define SET_BIT(reg,bit) ((reg) |= (1U << (bit)))
#define CLEAR_BIT(reg,bit) ((reg) &= ~(1U << (bit)))
#define TOGGLE_BIT(reg,bit) ((reg) ^= (1U << (bit)))

uint8_t modify_register(uint8_t reg) {

    SET_BIT(reg,2);
    SET_BIT(reg,7);
    CLEAR_BIT(reg,3);
    TOGGLE_BIT(reg,5);

    return reg;
}

int main() {
    uint8_t reg;
    scanf("%hhu", &reg);
    printf("%u", modify_register(reg));
    return 0;
}

Solving Approach

Perfect 🔥
Let’s explain this clearly and professionally — like in an interview.

We’ll go in this order:

1️⃣ Macro-Based Version (SET_BIT, CLEAR_BIT, TOGGLE_BIT)
2️⃣ Alternate Reusable BIT(n) Version

✅ 1️⃣ Macro-Based Version (Explicit Operation Macros)

#define SET_BIT(reg,bit)    ((reg) |=  (1U << (bit)))
#define CLEAR_BIT(reg,bit)  ((reg) &= ~(1U << (bit)))
#define TOGGLE_BIT(reg,bit) ((reg) ^=  (1U << (bit)))

uint8_t modify_register(uint8_t reg) {

    SET_BIT(reg, 2);
    SET_BIT(reg, 7);
    CLEAR_BIT(reg, 3);
    TOGGLE_BIT(reg, 5);

    return reg;
}

🧠 What This Version Does

Here, we define operation-specific macros.

Each macro directly represents one hardware action:

MacroMeaning
SET_BITForce bit to 1
CLEAR_BITForce bit to 0
TOGGLE_BITFlip the bit

🔍 Breaking Down One Macro

Example:

#define SET_BIT(reg,bit) ((reg) |= (1U << (bit)))

Step 1 — 1U << bit

Creates mask:

If bit = 5:

00000001 << 5
=
00100000

Step 2 — OR Operation

reg |= mask

OR forces that bit to 1.

🧠 Why This Version Is Good

✔ Very readable
✔ Clear intention
✔ Easy for beginners
✔ Explicit operation
✔ Matches hardware documentation

Example (STM32 style):

SET_BIT(GPIOA->ODR, 5);

Looks clean and expressive.

⚠ Why Parentheses Matter

((reg) |= (1U << (bit)))

Parentheses prevent macro expansion bugs when passing expressions.

✅ 2️⃣ Alternate Reusable BIT(n) Version (More Professional)

Now let’s look at this cleaner abstraction:

#define BIT(n) (1U << (n))

uint8_t modify_register(uint8_t reg) {

    reg |= BIT(2) | BIT(7);  // Set bits
    reg &= ~BIT(3);          // Clear bit
    reg ^= BIT(5);           // Toggle bit

    return reg;
}

🧠 What This Version Does

Instead of defining 3 operation macros, we define only:

#define BIT(n) (1U << (n))

Now we manually use operators:

  • |= → Set
  • &= ~ → Clear
  • ^= → Toggle

🧠 Why This Version Is More Reusable

Because:

  • You can combine masks easily
  • You avoid macro repetition
  • Cleaner and more scalable

Example:

reg |= BIT(2) | BIT(7);

You set two bits in one line.

With operation macros, you'd need two lines.

🔥 Comparison

FeatureOperation MacrosBIT(n) Version
Beginner Friendly✅ YesMedium
Less Code❌ Slightly more✅ Less
More FlexibleMedium✅ High
Industry StyleGood⭐ Excellent
Easier Multi-bit❌ No✅ Yes

🧠 Which One Is Used in Real Firmware?

Professional embedded code usually prefers:

#define BIT(n) (1U << (n))

Because:

  • Cleaner
  • Flexible
  • Easy to combine masks
  • Used in Linux kernel
  • Used in MCU HAL drivers

🎯 Interview Insight

If interviewer asks:

Which version would you prefer?

Strong answer:

I prefer the BIT(n) abstraction because it reduces macro duplication and allows flexible mask combinations, especially when configuring multi-bit registers.

That’s a solid embedded answer 🔥

🚀 Final Takeaway

Operation Macros → Educational, explicit
BIT(n) Version → Cleaner, scalable, production-style

 

 

Upvote
Downvote
Loading...

Input

0

Expected Output

164