- References
- Function Overloading
- Default Function Arguments
- Inline Function
- Dynamic Memory Allocation
- Placement New
- nullptr
- Namespaces
- Type Aliases
- Enum classes
- constexpr
- static_assert
- mutable Keyword
- auto Keyword
- Smart Pointers
- Basics of Classes
- Constructors
- Destructors
- Operator Overloading
- Copy Semantics
- Move Semantics
- Composition, RAII & Ownership
- Inheritance
- Polymorphism
- Abstraction
- Encapsulation
- Template
- Static Memory
- Friend Function
- this Pointer
- Function Pointer
- Lambdas and Callback Management
- Union
Default Function Arguments

Default Arguments allow a function to be called with fewer arguments than declared. If the caller omits specific arguments, the compiler automatically substitutes the default values provided in the function declaration.
This simplifies function calls for "standard" or "common" use cases without forcing the user to provide every single parameter.
Syntax & Usage
1. Basic Declaration
Defaults are assigned in the function declaration (prototype), usually in the .h file.
// Declaration (in Header)
// If 'parity' or 'stop_bits' are omitted, they default to 0 and 1.
void uart_init(int baud_rate, int parity = 0, int stop_bits = 1);
// Implementation (in .cpp) - Do NOT repeat default values here
void uart_init(int baud_rate, int parity, int stop_bits) {
// Hardware setup logic...
}2. Calling the Function
The compiler fills in the gaps from right to left.
uart_init(9600); // Equivalent to: uart_init(9600, 0, 1);
uart_init(115200, 1); // Equivalent to: uart_init(115200, 1, 1);
uart_init(57600, 2, 2); // Uses explicit values for all.Rules & Logic
- Trailing Only: You can only provide defaults for the rightmost arguments.
void func(int a, int b = 5);✅ OKvoid func(int a = 1, int b);❌ Error (Compiler cannot inferbif you only providea).
- No Skipping: You cannot skip an argument in the middle.
- To set
stop_bitsto 2, you must also provideparityexplicitly.
- To set
Relevance in Embedded/Firmware
1. Simplified Configuration APIs
Hardware peripherals often have dozens of settings (speed, mode, polarity, phase, interrupts). Most users only need the "standard" configuration.
Instead of forcing the user to populate a massive struct or pass 10 arguments, you provide defaults for the 90% case.
// User sees simple API:
timer.start(100); // 100ms, default mode, default priority
// Power users can override:
timer.start(100, TIMER_ONE_SHOT, HIGH_PRIORITY);2. Reducing Code Bloat (vs. Overloading)
If you used Function Overloading to achieve this, you would write 3 separate functions (one taking 1 arg, one taking 2 args, etc.).
With Default Arguments, there is only one function body in Flash memory. The compiler simply "pastes" the constant values at the call site.
3. Backward Compatibility
If you need to add a new parameter (e.g., uint8_t timeout) to an existing driver function, you can give it a default value. Existing code that calls the function without the new parameter will still compile without changes.
Common Pitfalls (Practical Tips)
| Pitfall | Details |
|---|---|
| ❌ Definition Conflict | Do not repeat the default values in the function definition (the .cpp file). It causes a compile error. Put them only in the header (.h). |
| ❌ Ambiguity with Overloading | If you have void func(int) and void func(int, int=0), calling func(5) is ambiguous. The compiler doesn't know which one to pick. |
| ❌ Value Binding | Default values are bound at compile time, not runtime. If you change the default value in the library but don't recompile the application code, the app will still use the old default. |
| ✅ Use Constants | Instead of magic numbers (int timeout = 100), use named constants (int timeout = DEFAULT_TIMEOUT) for readability. |
Concept understood? Let's apply and learn for real