Convert a macro into a function call - c

I have a created a macro which will print the timestamp with all the prints.
void timestamp()
{
struct timeval tv;
gettimeofday(&tv,NULL);
printf("%d",tv.tv_sec );
}
#define printf_all(format, ...) { \
static const char format_string[] = format; \
printf(format_string, ##__VA_ARGS__); \
timestamp(); \
}
int main()
{
printf_all("%d\n",10);
return 0;
}
I want to convert this macro into a function. But I am facing problems while passing in the arguments.
void printf_timestamp(static const char format_string[]) {
static const char format_string[] = format;
printf(format_string, ##__VA_ARGS__);
timestamp();
}

You can use vprintf:
int printf_timestamp(const char* fmt, ...) {
va_list args;
int result;
va_start(args, fmt);
result = vprintf(fmt, args);
va_end(args);
timestamp();
return result;
}

This is usually done using the vprintf() function, as orlp explained. However, that alone leaves you with a format that cannot be typechecked: Usually, your compiler interpretes the format string literal in every printf() call that it sees to determine whether the corresponding arguments have the right types.
Some compilers allow you to add support for this kind of type checking, here is the __attribute__(()) that is needed for gcc:
//within header
void printfTimestamp(const char* format, ...)
__attribute__((format(printf, 1, 2)));
//within implementation file
void printfTimestamp(const char* format, ...) {
va_list args;
va_start(args, format);
int result = vfprintf(stderr, format, args);
va_end(args);
timestamp();
return result;
}
The arguments to the attribute are the argument number with the format string (1) and the first variable argument position (2). As such, if you were to add an additional parameter to your function, you would declare it like this:
void myPimpedPrintf(int foo, const char* format, ...)
__attribute__((format(printf, 2, 3)));

For just adding a timestamp, I agree that vprintf() as proposed by orlp is the way to go. However, I think there is a valid argument in favor of macros, and that's the use of other compiler built-in macros like __LINE__, __FILE__, and __func__, which I personally find very useful for logging.
I generally use something like this with gcc and anything else that does comma swallowing.
#define log_debug(M, ...) do{ \
struct timespec _ts; \
double _ts_sec; \
clock_gettime(CLOCK_MONOTONIC, &_ts);\
_ts_sec = _ts.tv_nsec * 1e-9 + _ts.tv_sec; \
fprintf(stderr, "%.3f [DEBUG] (%s:%d) " M, _ts_sec, \
__func__, __LINE__, ##__VA_ARGS__); \
}while(0)
// usage:
log_debug("x=%d\n", x);
There are a couple "tricks" going on here you might not be familiar with.
The first of which is the do{}while() loop. This is a fairly common and largely portable C idiom for writing multi-statement macros. It lets you use the macro terminating it in a ; and allows declaration of scoped variables. However, is a statement, not an expression, so there's no "return value". Usually doesn't matter for printf() like macros, but be aware, this can bite you in other uses when trying to make function-like macros.
The other "trick" is the use of comma swallowing with the '##' operator. Read more here: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
Also, this takes advantage of the fact that back-to-back string literals are concatenated in C to form a single string literal. The downside is that this technique ONLY works with string literals, i.e. your format string cannot be in a variable.

Related

va_list in C: Creating a function that doesn't need a argument count like 'printf'

Using the <stdarg.h> header, one can make a function that has a variable number of arguments, but:
To start using a va_list, you need to use a va_start macro that needs to know how many arguments there, but the printf & ... that are using va_list don't need the argument count. How can I create a function that doesn't need the argument count like printf?
Let's say I want to create a function that takes a va_list and instead of using it, passes it to another function that requires a va_list? (so in pseudocode, it would be like void printfRipOff(const char* format, ...) {printf(format, ...);})
Let's say I want to create a function that takes a va_list and instead of using it, passes it to another function that requires a va_list?
Look at function vprintf( const char * format, va_list arg ); for one example of a function that takes a va_list as an input parameter.
It is basically used this way:
#include <stdio.h>
#include <stdarg.h>
void CountingPrintf(const char* format, ...)
{
static int counter = 1;
printf("Line # %d: ", counter++); // Print a Counter up front
va_list args;
va_start(args, format); // Get the args
vprintf(format, args); // Pass the "args" through to another printf function.
va_end(args);
}
int main(void) {
CountingPrintf("%s %s\n", "Hello", "World");
CountingPrintf("%d + %d == %d\n", 2, 3, 2+3);
return 0;
}
Output:
Line # 1: Hello World
Line # 2: 2 + 3 == 5
Functions like printf() and scanf() have the format string argument that tells them the number and types of the arguments that must have been provided by the function call.
If you're writing your own function, you must have some way of knowing how many arguments were provided and their types. It may be that they are all the same type. It may be that they're all pointers and you can use a null pointer to indicate the end of the arguments. Otherwise, you probably have to include a count.
You can do that as long as provided the called function expects a va_list. There are caveats (see C11 §7.16 Variable arguments) but they're manageable with a little effort.
A very common idiom is that you have a function int sometask(const char *fmt, ...) and a second function int vsometask(const char *fmt, va_list args), and you implement the first as a simple call to the second:
int sometask(const char *fmt, ...)
{
va_list args;
va_start(fmt, args);
int rc = vsometask(fmt, args);
va_end(args);
return rc;
}
The second function does the real work, of course, or calls on other functions to do the real work.
In the question, you say:
… va_start macro that needs to know how many arguments …
No; the va_start macro only needs to know which argument is the one before the ellipsis — the argument name before the , ... in the function definition.
In a comment, you say:
This is what I'm trying to write, but it didn't work.
string format(const char* text, ...)
{
// temporary string used for formatting
string formattedString;
initializeString(&formattedString, text);
// start the va_list
va_list args;
va_start(text, args);
// format
sprintf(formattedString.array, text, args);
// end the va_list
va_end(args);
return formattedString;
}
As noted by abelenky in a comment, you need to use vsprintf():
string format(const char* text, ...)
{
string formattedString;
initializeString(&formattedString, text);
va_list args;
va_start(text, args);
vsprintf(formattedString.array, text, args);
va_end(args);
return formattedString;
}
That assumes that the formattedString has enough space in the array for the formatted result. It isn't immediately obvious how that's organized, but presumably you know how it works and it works safely. Consider using vsnprintf() if you can determine the space available in the formattedString.
The printf and scanf family of functions don't need to be explicitly passed the length of the va_list because they are able to infer the number of arguments by the format string.
For instance, in a call like:
printf("%d %c %s\n", num, c, "Hello");
printf is able to examine the first parameter, the format string, and see that it contains a %d, a %c, and a %s in that order, so it can assume that there are three additional arguments, the first of which is a signed int, the second is a char and the third is a char* that it may assume is a pointer to a null-terminated string.
To write a similar function that does not need to be explicitly told how many arguments are being passed, you must find a way to subtly give it some information allowing it to infer the number and types of the arguments in va_list.

Print one more parameter with va_args

I have a function which implements a custom variant of printf.
Does anyone have a clue how I can print out one more parameter with va_list? My format is like "%d some text %s". I need a, to be printed as first parameter.
void func (int a, char *fmt, ...) {
va_list ap;
va_start (ap, fmt);
// vprintf(stdout, fmt, a, ap) //Can't do like this :(
vfprintf(fmt, a, ap); //Or like this :(
va_end(ap);
}
If a is always printed the same way, it shouldn't be part of the format passed in. You should instead print it separately.
In the example you gave, change your format string to "some text %s". Then your function can do this:
void func (int a, char *fmt, ...) {
va_list ap;
// first print the function specific fields
printf("%d ", a);
// then the user's format
va_start (ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
As noted in comments:
Redesign the interface
You would do best to redesign the interface so that the format string only applies to the ... (va_list) arguments; the fixed argument gets treated separately.
Standard reasons for wanting extra arguments are logging things like __FILE__ and __LINE__ (presumably not __func__ if you don't have C99 __VA_ARGS__ support — see below). You would probably do best to remove the option of caller-controlled formatting of those fixed arguments, leaving the fmt to process just the ... arguments.
If you can't redesign the interface
The fact that the %d is part of the format and the int value is not part of the va_list makes life tricky.
If you cannot, or decline to, change the rules for calling the function, you'll need to parse the format, for example separating it into the part up to (but not including) the second %, and use that format with the standalone argument; the remainder of the format is then passed to vprintf(). If you're on a POSIX system and in a multi-threaded program, you might want to use flockfile() and funlockfile() on stdout to ensure that they're treated as a single unit of output despite the multi-threading.
// Using C99 features
void func(int a, char *fmt, ...)
{
char *p1 = strchr(fmt, '%');
if (p1 == 0)
{
// No conversion specifications. Not puts(); it adds a newline
fputs(fmt, stdout);
return;
}
char *p2 = strchr(p1 + 1, '%');
if (p2 == 0)
{
// The user invoked func(1, "iteration %d:\n");?
printf(fmt, a);
return;
}
int buflen = p2 - fmt + 1;
char buffer[buflen];
memmove(buffer, fmt, buflen);
buffer[buflen-1] = '\0';
// flockfile(stdout); // Multi-threading
printf(buffer, a);
va_list ap;
va_start(ap, fmt);
vprintf(p2, ap);
va_end(ap);
// funlockfile(stdout); // Multi-threading
}
The code cheats; it uses a C99 VLA (variable length array) and also interleaved declarations and statements. In C90, therefore, you'd probably end up using malloc(), or perhaps a fixed size buffer (running risks of overflows), or a hybrid (use a fixed size buffer if the prefix of the format string is small enough to fit, or allocate (and free) if not).
You need to decide on the appropriate error handling strategies. Note that this isn't bullet-proof code. Calling func(a, "%% yield is %d; data is [%s]\n", data); throws another spanner in the works. Also, if you're on POSIX and someone passes "it is %2$s and %1$d things happened", you're in deep trouble.
Yes, I'm on POSIX system. But it is quite old, I am even not able to use approaches with __VA_ARGS__ macros as it appears in C99+ standards.
It's curious that you're on such an old system. However, that simply means you probably won't write code with the n$ notations in it, so it is one less thing to worry about. The multi-threading issue is less likely to be a problem either. And you can't use the other C99 features that were shown in my sample code.
You could look at the FFI (foreign function interface) library; I'm not at all sure it will help, though.
Based on previous answer to parse format, I've found a simple solution (if %d is always first):
void func (int a, char *fmt, ...) {
char *new_format = malloc(10*sizeof(char));
snprintf(new_format, 10, "%d", a);
strcat(new_format, (fmt+2));
va_list ap;
va_start (ap, fmt);
vprintf(stdout, new_format, ap);
va_end(ap);
}
Special Thanks to Jonathan Leffler

First argument is wrong when passing __VA_ARGS__

I'm trying to pass __ VA_ARGS __ to a function. For some reason the first argument is always wrong (seems like an address):
#define PRINTF_ERROR(format, ...) {\
PrintfError(format, __FUNCTION__, ##__VA_ARGS__);\
}
void PrintfError(const char* format, const char* function, ...)
{
va_list args;
va_start(args, format);
printf("%s(): ", function);
printf(format, args);
va_end(args);
}
For example, when trying to print the same variable:
"A = 0x20005524 A = 0x00000007"
Does anybody know why?
Thanks
There are two problem here.
First, va_start expects the last named parameter of the current function as its second parameter. In this case that would be function.
The second issue is that you're passing a va_list into printf. You should be calling vprintf instead.
void PrintfError(const char* format, const char* function, ...)
{
va_list args;
va_start(args, function); // pass "function" instead of "format"
printf("%s(): ", function);
vprintf(format, args); // call vprintf
va_end(args);
}
You've got the order of your parameters wrong. The one you pass to va_start() has to be the one before the ... because it's used to work out where the extra arguments start
So your function should look like this...
void PrintfError(const char* function, const char* format, ...)
{
va_list args;
va_start(args, format);
From man va_start:
void va_start(va_list ap, last);
[...]
DESCRIPTION
va_start()
[...]
The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.
So given
void PrintfError(const char* format, const char* function, ...)
just change
va_start(args, format);
to be
va_start(args, function);
Also this
printf(format, args);
(which probably is a typo) should be
vprintf(format, args);
Unrelated to your question, here
#define PRINTF_ERROR(format, ...) {\
PrintfError(format, __FUNCTION__, ##__VA_ARGS__);\
}
the curly braces are only half the way to make this safe.
Better do
#define PRINTF_ERROR(format, ...) do {\
PrintfError(format, __FUNCTION__, __VA_ARGS__);\
} while (0)
Also no need for the ##.

How to add an argument to a va_list

I have the following code:
int __dmasprintf (char **s, const char *format, ...) {
char buf[512];
va_list arg;
int ret;
va_start(arg,format);
ret = vsprintf(buf, format, arg);
va_end(arg);
*s = strdup(buf);
if (*s == NULL) return -1;
return 0;
}
I want to add an argument to the va_list arg before calling vsprintf() because my format contains 1 extra argument at the end.
How to add an argument (for example char * myarg) to the the va_list arg?
Or is it possible to pass vsprintf() a customized list?
You can't.
You either need to make two vsprintf (surely vsnprintf?) calls, or replace your function with a variadic macro, like
#define __dmasprintf(S, FMT, ...) ( \
(*S = do_dmasprintf(FMT, __VA_ARGS__, my_arg)) == NULL ? -1 : 0)
char *do__dmasprintf (const char *format, ...) {
char buf[512];
va_list arg;
int ret;
va_start(arg,format);
ret = vsnprintf(buf, sizeof(buf), format, arg);
va_end(arg);
char *s = strdup(buf);
return s;
}
Notes:
I replaced vsprintf with vsnprintf. There's no reason to use the former here (or pretty much anywhere else)
you ignore ret. Should you?
I kept the macro argument layout similar to the original, but since __VA_ARGS__ must be one-or-more arguments (it can't be empty), that means at least one argument is required after FMT. Just remove the FMT argument entirely if you want to allow zero arguments after it.
There is unfortunately no direct way to do that. There is a reason for that : the stdarg macros take the address in the stack of the last known parameter, and then directly iterate the stack.
If you can use macros, #Useless provided a nice solution - beware, macros can have side effects when you pass variables pre- or post-fixed with ++ or --.
If you want to avoid macros, you will have to write your own variant of vsprintf. No problem for it, just find a source for C stdlib (GNU libc could be a nice start point) and be brave ... hope you can use macros !

#define and functions with variable length arguments

I have zillions of my_printf() function calls in a huge program. I now want to convert them all so that the function takes a new integer argument (call it x) without having to edit the zillions of calls. If my_printf only ever took exactly one string argument then I could do something like this:
#define my_printf(str) _my_printf(x,str)
void _my_printf(int x,char *str) // changed from my_printf(char *str)
{
// stuff
}
But as my_printf takes a variable number of arguments I'm not sure how to do it. Can it be done?
EDIT: for those wondering why I should want to do such a thing, here's a related example:
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
#define function(x) _function(__FILE__,__LINE__,x)
#else // speed critical optimised mode
#define function(x) _function(x)
#endif
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
void _function(char *file,int line,int x)
#else
void _function(int x)
#endif
{
// stuff
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
if (something_went_wrong)
{
printf("Cock up in function when called from %s line %d\n",file,line);
}
#endif
}
You may use C99 variadic macros:
#define my_printf(...) my_printf_(x, __VA_ARGS__)
As Microsoft's implementation suppresse trailing commas, the str argument can be added explicitly
#define my_printf(str, ...) my_printf_(x, str, __VA_ARGS__)
but this would lead to a syntax error in standard C when invoked without variadic arguments
my_printf("foo")
or an empty argument list
my_printf("foo",)
Therefore, I'd go with the first version.
If the code can be compiled as C99 code, you can define a variadic macro
#define my_printf(str, args...) _my_printf(x, str, ##__VA_ARGS__)
The preprocessor will replace the arguments ... and the GNU preprocessor will remove the trailing comma in case the macro is invoked only with the str argument.
The best thing is of course to bite the bullet and edit the code. Otherwise you're creating a "mystery", that needs to be solved by all future maintainers of the code. Even if that's only you, this is exactly the kind of clever trick that you will forget all about. It sucks to come back, and be puzzled by strange pointless-seeming macros.
That said, if you're using a GNU toolchain, you can perhaps look into using varargs macros.
Not with standard C89 macros, you can't. However you can get the same effect using functions, by breaking out the main part of your my_printf function into a vmy_printf function, analagous to the standard vprintf:
#include <stdarg.h>
int vmy_printf(int x, const char *format, va_list ap)
{
/* main body of my_printf goes here, taking its varargs from ap */
}
/* new_my_printf(), for callers who know about the x parameter */
int new_my_printf(int x, const char *format, ...)
{
int n;
va_list ap;
va_start(ap, format);
n = vmy_printf(x, format, ap);
va_end(ap);
return n;
}
/* my_printf(), for the old callers who don't know about x */
int my_printf(const char *format, ...)
{
int n;
va_list ap;
va_start(ap, format);
n = vmy_printf(DEFAULT_X, format, ap);
va_end(ap);
return n;
}
(This kind of thing is why those v... versions of all the standard varargs functions exist.)
If my_printf already takes a variable number of arguments, I'm not sure why you need to wrap 'one more argument' in a macro... Just insert the new calls with the extra argument and be done with it; the old calls should still work as expected.
A simple solution to this problem is...
#define my_printf(x) printf x
(note the missing braces)
To call it, use:
my_printf((any number of arguments))
(note the double braces)

Resources