I have the following log function
void log_error(char * file_name, int line_num, int err_code) {
printf("%s:%d:%s\n", file_name, line_num, get_err_str(err_code));
}
I want to change this to have the option to pass a custom format string and args for additional information something like
void log_error(char * file_name, int line_num, int err_code, ...) {
va_list ptr;
char * fmt;
printf("%s:%d:%s", file_name, line_num, get_err_str(err_code));
va_start(ptr, err_code);
fmt = va_arg(ptr, char *);
vprintf(fmt, ptr);
printf("\n");
}
but I don't want to enforce passing this extra info, so I might not get fmt and the required extra arguments which might cause the code to fail, is there a way to check if there are variadic args before trying to access them? Or the only option for my use case is defining 2 different function, like so
void log_error(char * file_name, int line_num, int err_code) {
printf("%s:%d:%s\n", file_name, line_num, get_err_str(err_code));
}
void log_error(char * file_name, int line_num, int err_code, const char * fmt, ...) {
va_list ptr;
printf("%s:%d:%s", file_name, line_num, get_err_str(err_code));
va_start(ptr, err_code);
vprintf(fmt, ptr);
printf("\n");
va_end(ptr);
}
You can't check for variadic arguments in functions without at least one non-variadic argument that tells you what is going on, but you CAN use a variadic macro that expands to the "right" variadic function call. Since you are probably already using a macro to supply __FILE__ and __LINE__, you can probably do something like:
// this is the function that will be called by the macro
void log_error_func(char * file_name, int line_num, int err_code, const char *fmt, ...);
// this is the macro that will be used to log
#define log_error(CODE, ...) log_error_func(__FILE__, __LINE__, CODE, "" __VA_ARGS__)
Now you can use things like
log_error(42, "this error has args: %d, %d, %d", 1, 2, 3);
as well as
log_error(5); /* no args here */
and they'll work as one would expect. The use of "" in a macro like this requires that the format arg (if present) be string literal, so the empty string will be properly prepended.
Your function doesn't have any way of knowing whether or not a format string has been passed. So the best thing to do is to make it an explicit parameter.
void log_error(char * file_name, int line_num, int err_code, char * fmt, ...) {
va_list ptr;
printf("%s:%d:%s", file_name, line_num, get_err_str(err_code));
va_start(ptr, fmt);
vprintf(fmt, ptr);
va_end(ptr);
printf("\n");
}
For a function like this, I would expect that a message string would have to be passed.
is there a way to check if there are variadic args before trying to access them?
No.
the only option for my use case is defining 2 different function, like so
Generally, yes, or similar.
You can make log_error a macro, and overload the macro on the number of arguments. 3 arguments would go to the first version, more would go to the variadic one.