Question.6
A template driver validates that the register type is the correct width:
template<typename RegT>
class PeripheralDriver {
static_assert(sizeof(RegT) == 4,
"Register type must be 32-bit");
// ...
};
PeripheralDriver<uint16_t> timer; // Instantiate with 16-bit typeWhat happens?
In C, we often use #error preprocessor directives or runtime checks like assert() to catch bugs.
assert(x > 0) runs on the device. If it fails, your firmware crashes or halts while the user is using it.static_assert runs on the compiler. If it fails, your code refuses to compile.This is the ultimate safety net: catching fatal configuration errors before the firmware is even generated.
1. Basic Usage
It takes a boolean constant expression and an optional error message.
// Syntax: static_assert(condition, "Error Message");
// Ensure this code is compiled for a 32-bit system
static_assert(sizeof(void*) == 4, "Error: Code requires 32-bit architecture");
// Ensure integer is large enough
static_assert(sizeof(int) >= 4, "Error: int must be at least 4 bytes");2. Validating Struct Sizes (Padding Check)
Crucial for memory-mapped structs or communication packets.
struct Packet {
uint8_t id;
uint32_t payload;
};
// Check if compiler added padding bytes
static_assert(sizeof(Packet) == 5, "Error: Packet struct has padding! Use #pragma pack.");| Feature | assert() (C/C++) | static_assert (C++) |
|---|---|---|
| When it runs | Runtime (on the CPU). | Compile-Time (on PC). |
| Cost | CPU Cycles + Flash code size. | Zero overhead (0 bytes). |
| Failure | Firmware crash / infinite loop. | Compilation Error. |
| Condition | Any variable/state. | Must be constexpr (known at compile time). |
1. Protocol Packet Safety
When defining structs for UART/SPI/CAN frames, compiler padding can silently break communication.
static_assert(sizeof(Frame) == 8, ...) ensures that if someone adds a field or changes a type, the build breaks immediately, preventing hard-to-debug communication failures.
2. Buffer Configuration Checks
If you have a circular buffer that requires a power-of-two size for efficient bitwise wrapping:
constexpr int BUF_SIZE = 100; // Oops, not power of 2
static_assert((BUF_SIZE & (BUF_SIZE - 1)) == 0, "Buffer size must be power of 2");3. Validating Type Aliases
If you switch platforms (e.g., STM32 to AVR), types like int might change size.
static_assert ensures your assumptions (e.g., "I need a 64-bit timestamp") hold true on the new hardware.
| Pitfall | Details |
|---|---|
| ❌ Runtime Variables | You cannot check variables that change at runtime.
|
| ❌ Meaningless Messages | Don't just say "Error". Be descriptive: "PLL Config Error: System clock too high for selected voltage range." This helps other developers fix the config file instantly. |
| ✅ Library Validation | If you write a template library (e.g., a generic Ring Buffer), use static_assert to prevent users from instantiating it with invalid types (e.g., a buffer of void). |