19. Log Message Timestamp

Create a function that logs messages from firmware.

The function must accept:

  • A string message (required)
  • A boolean flag indicating whether a timestamp should be included (optional; default = false)

If the timestamp flag is:

  • false → print only the message
  • true → print a simulated timestamp followed by the message

Use a fixed timestamp value of 123456 for this exercise.

 

The final printed format must be:

Without timestamp:

message

With timestamp:

[123456] message

 

In main():

  • Read mode
    • 0 → call the function using only the message (default behavior)
    • 1 → call the function with timestamp enabled (true)
  • Read the message as a single word.

 

Example 1

Input:

0 Hello

Output:

Hello

 

Example 2

Input:

1 Alert

Output:

[123456] Alert

 

Constraints:

  • Use a default argument for the timestamp flag
  • Do not create overloaded functions

 

 

 

Need Help? Refer to the Quick Guide below

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

  1. Trailing Only: You can only provide defaults for the rightmost arguments.
    • void func(int a, int b = 5); ✅ OK
    • void func(int a = 1, int b); ❌ Error (Compiler cannot infer b if you only provide a).
  2. No Skipping: You cannot skip an argument in the middle.
    • To set stop_bits to 2, you must also provide parity explicitly.

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)

PitfallDetails
❌ Definition ConflictDo 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 OverloadingIf 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 BindingDefault 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 ConstantsInstead of magic numbers (int timeout = 100), use named constants (int timeout = DEFAULT_TIMEOUT) for readability.