C puzzle...How Can I pass variadic arguments into a macro? - c

I got stuck here...
#include <stdio.h>
#define DBG_LVL(lvl, stmt) \
do{ \
if(lvl>1) printf stmt; \
}while(0)
#define DBG_INFO(stmt) DBG_LVL(1, stmt)
#define DBG_ERROR(stmt) DBG_LVL(2, stmt)
int main()
{
DBG_INFO(("hello, %s!\n", "world"));
DBG_ERROR(("crazy, %s!\n", "world"));
return 0;
}
As you can see, the code above uses macros like "DBG_INFO" or "DBG_ERROR" to control debug information level.
Now for some reason, I have to replace DBG_LVL() with a new function.
void myprint(int lvl, const char * format, ...);
The only difference is the debug level is taken as its fisrt parameter.
I was thinking:
#define DBG_LVL(lvl, stmt) myprint(lvl, stmt)
Of course it failed, because the "stmt" expression includes parentheses around.
Then I googled around trying to find a way to strip the parentheses, seems there's nothing could help.
I also tried some tricks to pass parameters into "stmt", still failed... :(
Can you help me?

# define EXPAND_ARGS(...) __VA_ARGS__
# define DBG_LVL(lvl, stmt) myprint(lvl, EXPAND_ARGS stmt);

Don't write this as a macro.
Write instead an ordinary varargs function:
void DBG_LVL(int level, char *fmt, ...)
{
if (level < 1) return;
va_list args;
va_start(args, fmt);
vaprintf(fmt, args);
va_end(args);
}
For myprint(), define a similar vamyprint(int lvl, const char *format, va_list ap) as well, and forward the same way.

Related

How to use parameters const char *format in custom printf

I'm looking for a function that print log information, in order to debug my program.
This function must look at a boolean and decide if write the log in a file or to the console.
int useFile;
int log_informations( ? )
{
if(useFile)
{
// open/close FILE *pf omitted
fprintf(pf, ? );
}
else
{
printf( ? );
}
return 0;
}
int main()
{
int answer = 42;
log_informations("The answer is %d.", answer);
return 0;
}
Can you help me with the parameter? I did not found any reference.
NB: In this question I made things clear and simpler as they were in my context, so I do not need workaround but, possibly, a simple answer.
Thank you in advance ;)
As other mentioned, you don't need to actually write a function. A macro could help here:
#define LOG(fmt, ...) fprintf(logToFile ? fileLogger : stdout, fmt, ##__VA_ARGS__)
To answer your question you can look at how printf and vprintf work:
int printf(const char *format, ...);
int vprintf(const char *format, va_list arg);
printf is a variadic function and you want to provide your own version that wraps vprintf and vfprintf.
#include <stdarg.h> // needed for va_list, va_start, and va_end.
int my_printf(const char *format, ...)
{
va_list ap;
int ret;
va_start(ap, format);
if (useFile) ret = vfprintf(pf, format, ap);
else ret = vprintf(format, ap);
va_end(ap);
return ret;
}
EDIT: as #phuclv mentioned, if you want to include file, line, and/or function information in your log a macro is the only way. For example, for appending file and line information you could do something like this:
#define LOG(fmt, ...) fprintf(logToFile ? fileLogger : stdout, __FILE__ ":" STRINGIFY(__LINE__) " " fmt, ##__VA_ARGS__)
#define STRINGIFY_HELPER(x) #x
#define STRINGIFY(x) STRINGIFY_HELPER(x)
You need STRINGIGY for __LINE__ because it is an int.

How to define a c macro with multiple statement

I am trying to define a macro that has two line/statements, it's like:
#define FLUSH_PRINTF(x) printf(x);fflush(stdout);
but it can't work due to the limit that C macros cannot work with ';'.
Is there any reasonable way to work around it?
P.S.: I know the upper example is weird and I should use something like a normal function. but it's just a simple example that I want to question about how to define a multiple statement Macro.
This is an appropriate time to use the do { ... } while (0) idiom.
This is also an appropriate time to use variadic macro arguments.
#define FLUSH_PRINTF(...) \
do { \
printf(__VA_ARGS__); \
fflush(stdout); \
} while (0)
You could also do this with a wrapper function, but it would be more typing, because of the extra boilerplate involved with using vprintf.
#include <stdarg.h>
#include <stdio.h>
/* optional: */ static inline
void
flush_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
fflush(stdout);
}
Use the multiple expression in macro
#define FLUSH_PRINTF(x) (printf(x), fflush(stdout))

Enable DEBUG Message during run time

I want to enable "printf("macro MESSAGE is %d\n",MESSAGE);" during run time. For example , if i give argument 10 in run time, it should print the message. if it is not given, it should not print this message.Is it possible?
#include <stdio.h>
#define MESSAGE 10
int foo;
void main(int argc, char *argv[])
{
foo = atoi(argv[1]);
printf("foo is %d\n", foo);
#if MESSAGE==foo
printf("macro MESSAGE is %d\n",MESSAGE);
#endif
}
We can define a macro conditionally based on a preprocessor macro to control in compile time what the definition of the macro is:
#if DEBUGGING
#define debug(format, ...) fprintf(stderr, format, __VA_ARGS__)
#else
#define debug(format, ...) ()
#endif
The debug macro itself is actually an example in GCC's manual.
Or, we could make a similar function that checks in run time the value of some variable:
#include <stdarg.h>
#include <stdio.h>
int debugging = 10;
void debug(int msglevel, const char *fmt, ...)
{
if (debugging < msglevel) return;
va_list va;
va_start(va, fmt);
vfprintf(stderr, fmt, va);
va_end(va);
}
...
debug(10, "Error: %s\n", "some explanation");
A full function makes it easier to do a greater than comparison for the verbosity level. Of course we could still have an alternate definition of r the function on compile time to fully disable it. For the varargs, see the va_arg(3) man page.

printf macro for compiler with and without support for VARIADIC

Please help me writing a printf macro for one compiler that supports VARIADIC and another that does not.
For instance:
#ifdef HAVE__VA_ARGS
printf macro
#else
printf macro
An solution with VARIADIC can be lock like this.
#define my_printf(_format, ...) { \
printf(_format, __VA_ARGS__); \
}
And if you really have an compiler without VARIADIC, then you have to implement an function with an variable argument list.
#include <stdarg.h>
#include <std.h>
int my_printf(const char *format, ...)
{
va_list ap;
va_start(ap, dst);
return vprintf(format, ap);
}

Good Verbosity Macro (C99)

I'm looking to write what I would imagine is a fairly common macro. I want to emulate the repeated "-v" options on many POSIX programs by defining a bunch of macros of the following form:
#define V1(str, ...) if(optv >= 1){printf("%s: "str,prog,__VA_ARGS__);}
int main(int argc, char* argv[])
{
// ... stuff ...
int i = 1;
V1("This contains a variable: %d\n",i);
}
// Output:
// ./program: This contains a variable: 1
where optv counts the number of "-v" options found on the command line and prog contains the program name (neither shown). This works well, but the problem is that I have to use a variable. V1("Output") will generate a compiler error. I could always use V1("Output%s","") but there should be a cleaner solution.
The GNU C preprocessor has a special feature that lets you delete the trailing comma when there are no arguments filling the variadic portion by prepending the token-pasting operator ## to __VA_ARGS__:
#define V1(str, ...) if(optv < 1); else printf("%s: "str,prog, ## __VA_ARGS__)
Alternatively, if you wish to remain fully C99 compliant, you could incorporate the the format string parameter into the ellipsis, but in this instance you'll also need to refactor your code since you want to include the extra prog parameter between the format string and the varargs. Something like this might work:
#define V1(...) if(optv < 1); else myprintf(prog, __VA_ARGS__)
int myprintf(const char *prog, const char *fmt, ...)
{
// Print out the program name, then forward the rest onto printf
printf("%s: ", prog);
va_list ap;
va_start(ap, fmt);
int ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
Then, V1("Output") expands to myprintf(prog, "Output") without using any non-C99 compiler extensions.
EDIT
Also note that I inverted the if condition in the macro, due to some weird issues that can arise if you invoke the macro inside an if statement without braces—see this FAQ for a detailed explanation.
Why don't you use 2 different macros for each verbosity level; one which prints a message and variable, and one which just prints a message?
You should probably write yourself a small support function so that you can do the job cleanly:
extern void vb_print(const char *format, ...);
#define V1(...) do { if (optv >= 1) vb_print(__VA_ARGS__); } while (0)
I assume that both optv and prog are global variables. These would go into a header (you wouldn't write them out in the programs themselves, would you?).
The function can be:
#include <stdio.h>
#include <stdarg.h>
extern const char *prog;
void vb_print(const char *format, ...)
{
va_list args;
va_start(args, format);
printf("%s:", prog);
vprintf(format, args);
va_end(args);
}
There's no rocket science in there. You can tweak the system to your heart's content, allowing a choice of where the information is written, flushing the output, ensuring there's a newline at the end, etc.
Try this:
#define V1X(str, ...) if(optv >= 1) {printf("%s: "str,prog,__VA_ARGS__);} else
#define V1(...) V1X(__VA_ARGS__,0)
I believe that fixes the problem you described, and the else at the end fixed another problem.

Resources