preprocessor-toolchain · intermediate · ~15 min

Safe Variadic Debug Formatter

Combine preprocessor variadic patterns with runtime vsnprintf formatting and bounds checking.

Challenge

C99 variadic macros (... and __VA_ARGS__) enable flexible logging frameworks that accept variable numbers of formatting arguments. Defensive formatters route variable arguments through vsnprintf with buffer boundary checks.

Your Task

Implement:

int log_message_formatted(char *buf, size_t cap, const char *prefix, const char *fmt, ...);

Rules

  1. If buf == NULL, prefix == NULL, fmt == NULL, or cap == 0, return -1.
  2. First print the prefix: "[PREFIX] ".
  3. Format the variadic arguments according to fmt directly after the prefix.
  4. If the combined output does not fit completely within cap (including NUL), return -1 without buffer overflow.
  5. On success, return total characters written (excluding NUL).

Example

char out[64];
log_message_formatted(out, sizeof(out), "INFO", "User %s logged in with ID %d", "alice", 42);
// out is: "[INFO] User alice logged in with ID 42"

Input format

buf: output buffer; cap: capacity; prefix: tag string; fmt: printf format string; variadic args.

Output format

Returns total characters written, or -1 on truncation/invalid arguments.

Constraints

Must use stdarg.h with vsnprintf. Safe truncation handling.

Starter code

#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>

/* Format "[PREFIX] formatted_msg" into buf. Return characters written or -1 on error/truncation. */
int log_message_formatted(char *buf, size_t cap, const char *prefix, const char *fmt, ...) {
    (void)buf; (void)cap; (void)prefix; (void)fmt;
    return -1;
}

Common mistakes

Forgetting va_end; buffer overflow on prefix concatenation; ignoring vsnprintf truncation.

Edge cases to handle

Buffer capacity exact fit succeeds; buffer 1 byte short returns -1; NULL pointers return -1.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.