What is the implementation principle and usage methods of variadic functions in C language?
Variadic Function Basics:
-
Basic Definition
c#include <stdarg.h> int sum(int count, ...) { va_list args; va_start(args, count); int total = 0; for (int i = 0; i < count; i++) { total += va_arg(args, int); } va_end(args); return total; } int result = sum(3, 10, 20, 30); -
Core Macros
cva_list args; // Declare argument list va_start(args, last); // Initialize argument list va_arg(args, type); // Get next argument va_end(args); // Clean up argument list
Typical Application Scenarios:
-
Formatted Output
cvoid debug_print(const char *format, ...) { va_list args; va_start(args, format); #ifdef DEBUG vprintf(format, args); #endif va_end(args); } debug_print("Value: %d, String: %s\n", 42, "Hello"); -
Custom Error Handling
cvoid error_handler(int code, const char *format, ...) { va_list args; va_start(args, format); fprintf(stderr, "Error %d: ", code); vfprintf(stderr, format, args); fprintf(stderr, "\n"); va_end(args); } error_handler(404, "File %s not found", "config.txt"); -
String Building
cchar* string_build(const char *format, ...) { va_list args; va_start(args, format); int size = vsnprintf(NULL, 0, format, args); va_end(args); char *buffer = malloc(size + 1); if (buffer) { va_start(args, format); vsnprintf(buffer, size + 1, format, args); va_end(args); } return buffer; }
Advanced Usage:
-
Type Safety Checking
cvoid safe_printf(const char *format, ...) { va_list args; va_start(args, format); const char *p = format; while (*p) { if (*p == '%') { p++; switch (*p) { case 'd': va_arg(args, int); break; case 'f': va_arg(args, double); break; case 's': va_arg(args, char*); break; } } p++; } va_end(args); } -
Variadic Argument Counting
cint count_args(int first, ...) { if (first == -1) return 0; va_list args; va_start(args, first); int count = 1; int value; while ((value = va_arg(args, int)) != -1) { count++; } va_end(args); return count; } -
Passing Variadic Arguments
cvoid wrapper_printf(const char *format, ...) { va_list args; va_start(args, format); vprintf(format, args); va_end(args); }
Important Considerations:
-
Argument Type Matching
c// Dangerous: Type mismatch void example(const char *format, ...) { va_list args; va_start(args, format); int i = va_arg(args, int); // Must match actual argument type double d = va_arg(args, double); va_end(args); } -
Default Argument Promotions
cvoid promoted_args(...) { va_list args; va_start(args, 0); // char and short are promoted to int // float is promoted to double int i = va_arg(args, int); double d = va_arg(args, double); va_end(args); } -
Memory Management
cvoid process_strings(...) { va_list args; va_start(args, 0); char *str; while ((str = va_arg(args, char*)) != NULL) { // Process string // Note: Don't free string } va_end(args); }
Practical Application Examples:
-
Logging System
ctypedef enum { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR } LogLevel; void log_message(LogLevel level, const char *format, ...) { const char *level_str[] = {"DEBUG", "INFO", "WARN", "ERROR"}; printf("[%s] ", level_str[level]); va_list args; va_start(args, format); vprintf(format, args); va_end(args); printf("\n"); } -
Configuration Parsing
cvoid parse_config(const char *key, ...) { va_list args; va_start(args, key); void *ptr; while ((ptr = va_arg(args, void*)) != NULL) { // Parse config and store to pointer } va_end(args); } int port, timeout; parse_config("server", &port, &timeout, NULL); -
Array Summation
cdouble sum_array(int count, ...) { va_list args; va_start(args, count); double sum = 0.0; for (int i = 0; i < count; i++) { sum += va_arg(args, double); } va_end(args); return sum; } double result = sum_array(3, 1.5, 2.5, 3.5);