In embedded systems programming, understanding low-level operations like bitwise and logical operators is essential for efficient memory usage and hardware control. Below is a practical explanation of common operators such as |, &, <<, >>, &&, ||, ++i, and i++, along with illustrative code examples.
Data Types and Binary Representation
Key data types in C (on most 32-bit embdeded platforms):
char: 1 byte (8 bits)int: 4 bytes (32 bits), signed by default
A 32-bit signed integer ranges from -2,147,483,648 to 2,147,483,647. Values beyond this wrap around due to two’s complemant representation.
Bitwise OR (|)
The OR operator sets a bit to 1 if either operand has a 1 in that position.
uint32_t val = 48; // 0x00000030 → binary: 0011 0000
uint32_t result = val | 0xFF; // 0x000000FF → result = 0x000000FF (255)
Commonly used to set specific bits without affecting others.
Bitwise AND (&)
The AND operator yields 1 only if both operands have 1 in that bit position.
uint32_t val = 48; // 0x30
uint32_t masked = val & 0xFF; // Keeps lower 8 bits → 0x30 (48)
Frequently used to extract or mask out portions of a value (e.g., isolating a byte).
Left and Right Shifts (<<, >>)
Shift operators move bits left or right:
x << n: shifts bits left bynpositions (equivalent to multiplying by 2ⁿ)x >> n: shifts bits right bynpositions (equivalent to dividing by 2ⁿ for unsigned values)
uint8_t byte = 48; // 0b00110000
uint8_t shifted = byte << 2; // 0b11000000 → 192
Used in packing/unpacking multi-byte data (e.g., combining two bytes into a 16-bit value):
uint8_t high = 48, low = 78;
uint16_t combined = (high << 8) | low; // 0x304E
Logical Operators (&&, ||)
These evaluate boolean truthiness (non-zero = true):
a && b: true only if bothaandbare non-zeroa || b: true if eitheraorbis non-zero
Short-circuit evaluation appleis: in a && b, if a is false, b is not evaluated.
Increment Operators: ++i vs i++
++i(pre-increment): incrementsi, then returns the new valuei++(post-increment): returns the current value ofi, then increments it
int i = 1;
if (i++ == 1) { /* true — uses original value */ }
// now i = 2
if (++i == 3) { /* true — increments first to 3 */ }
Practical Example
#include <stdio.h>
#include <stdint.h>
int main() {
uint32_t d1 = 48, d2 = 78;
uint32_t packed = ((d1 & 0xFF) << 8) | (d2 & 0xFF); // 0x304E
uint32_t shifted = (d1 & 0xFF) >> 4; // 0x03
printf("Packed: 0x%04X\n", packed); // Output: 0x304E
printf("Shifted: 0x%X\n", shifted); // Output: 0x3
int x = 1;
if (x++ == 1 && ++x == 3) {
printf("Condition met\n"); // Executes
}
return 0;
}