In embedded and firmware systems, hardware registers are often manipulated using bitwise operations such as OR and AND to set, clear, or mask specific bits.
Your task is to implement a C++ class named Reg32 that represents a 32-bit hardware register and supports controlled bitwise operations using operator overloading.
The register must store an unsigned 32-bit value and allow modification using bitwise OR and AND assignments, similar to how registers are manipulated in low-level firmware code.
Task Requirements
Implement a class Reg32 that:
uint32_t value internally.reg |= x; → Performs a bitwise OR between the register value and xreg &= x; → Performs a bitwise AND between the register value and xoperator uint32_t() const;Program Flow
initial_value or_value and_value
Reg32 object initialized with initial_value.reg |= or_value;
reg &= and_value;
Input Format
Three space-separated unsigned integers:
initial_value or_value and_value
Output Format
A single unsigned integer representing the final register value after both operations.
Example
Input:
8 5 14
Binary Steps:
8 = 1000₂
5 = 0101₂ → OR → 1101₂ (13)
14 = 1110₂ → AND → 1100₂ (12)
Output:
12
Constraints
|= and &=operator uint32_t() must be implementeduint32_t for all register-related values
In C, operators like +, -, ==, or [] only work on built-in types (int, float). If you have a custom struct (e.g., Complex), you have to write clumsy functions like add_complex(a, b).
In C++, Operator Overloading allows you to define how standard operators behave for your custom classes. This lets you treat hardware objects or math structures just like native types.
1. Basic Arithmetic (+, -)
Making complex data types (like Vectors or Fixed-Point numbers) intuitive to use.
class Vector {
public:
int x, y;
Vector(int x, int y) : x(x), y(y) {}
// Overload '+' operator
Vector operator+(const Vector& other) const {
// Return a new object with the sum
return Vector(this->x + other.x, this->y + other.y);
}
};
// Usage
Vector v1(1, 2), v2(3, 4);
Vector v3 = v1 + v2; // v3 is (4, 6). Reads like math!2. Array Subscript ([])
Allows a driver class to access internal memory or hardware buffers like a standard C array.
class EEPROM {
uint32_t base_addr;
public:
// Overload [] to read byte at offset
uint8_t operator[](int offset) {
return *(volatile uint8_t*)(base_addr + offset);
}
};
EEPROM memory;
uint8_t val = memory[5]; // Reads hardware address (base + 5)3. Comparison (==)
Simplify checking sensor states.
bool operator==(const SensorData& a, const SensorData& b) {
return (a.id == b.id) && (a.val == b.val);
}
if (current_reading == last_reading) { /* ... */ }How It Works (Syntactic Sugar)
| Expression | Compiler Translates To |
|---|---|
a + b | a.operator+(b) |
a == b | a.operator==(b) |
obj[i] | obj.operator[](i) |
ptr->x | ptr.operator->() (Smart Pointers) |
1. Fixed-Point Math
On microcontrollers without an FPU (Floating Point Unit), we often use integers to represent decimals (e.g., 100 = 1.00).
By wrapping this in a class and overloading +, -, *, /, you can write math code that looks like standard float math but compiles to efficient integer instructions.
2. Hardware Buffers
Overloading [] allows you to create "Safe Arrays" that check bounds before accessing memory.
uint8_t& operator[](int i) {
assert(i < SIZE); // Safety check in Debug mode
return buffer[i];
}3. Bit Manipulation
You can overload | and & for enum class types (which don't support them by default) to create type-safe flag systems.
| Pitfall | Details |
|---|---|
| ❌ Changing Meaning | Don't overload + to do subtraction. Operators should follow "Principle of Least Astonishment." If a + b deletes a file, no one will understand your code. |
| ❌ Logical Operators | Avoid overloading && and ` |
| ❌ Unary vs Binary | operator++() (Prefix) and operator++(int) (Postfix) have different signatures. Mixing them up causes infinite recursion or wrong behavior. |
| ✅ Zero Overhead | If implemented correctly (often inline), operator overloading has zero CPU cost compared to a manual function call. |