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))
Related
I need to change a implementation of Macro(LOGGING_MACRO)
printf into syslog.
Macro Usage :
LOGGING_MACRO(5,("Value of x,y=%d,%d\n",x,y));
Def1 :
#define LOGGING_MACRO(loglevel,str) printf str;
Def2 :
#define LOGGING_MACRO(loglevel,str) syslog(loglevel,str);
Note : I cannot change the macro format :(
Def2 throws error as syslog will not accept 'str'(2nd arg) with front & back braces. [But working fine in Def1 with printf ]
Kindly suggest how to remove the 1st & last braces from 'str' inside the macro before passing 'str' to syslog.
Example below will work in single thread application:
char* custom_log(const char *fmt, ...) {
static char outputString[200]; //Adjust your size for maximal log value
va_list args;
va_start(args, fmt);
vsprintf(outputString, fmt, args);
va_end(args);
return outputString;
}
Then modify your macro to:
#define LOGGING_MACRO(loglevel,str) syslog(loglevel, custom_log str)
Remember, this works only in single-thread mode and make sure, custom_log function is visible where custom_log function is called.
For multi-thread, you might update it like this:
#define LOGGING_MACRO(loglevel,str) do {\
mutex_lock(); /*Lock your mutex for debug print*/ \
syslog(loglevel, custom_log str); /*Debug*/ \
mutex_unlock(); /*Unlock mutex*/ \
} while (0)
Keep in mind that you have to write mutex_lock and mutex_unlock functions for your requirements in your system to lock only debug functions between multi threads.
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);
}
This might sound like an interview question but is actually a practical problem.
I am working with an embedded platform, and have available only the equivalents of those functions:
printf()
snprintf()
Furthermore, the printf() implementation (and signature) is likely to change in the near future, so calls to it have to reside in a separate module in order to be easy to migrate later.
Given that, can I wrap logging calls in some function or macro? The goal is that my source code calls THAT_MACRO("Number of bunnies: %d", numBunnies); in a thousand places, but calls to the above functions are seen only in a single place.
Compiler: arm-gcc -std=c99
Edit: just to mention, but post 2000 best practices and probably a lot earlier, inline functions are far better than macros for numerous reasons.
There are 2 ways to do this:
Variadric macro
#define my_printf(...) printf(__VA_ARGS__)
function that forwards va_args
#include <stdarg.h>
#include <stdio.h>
void my_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
There are also vsnprintf, vfprintf and whatever you can think of in stdio.
Since you can use C99, I'd wrap it in a variadic macro:
#define TM_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#define TM_SNPRINTF(s_, sz_, f_, ...) snprintf((s_), (sz_), (f_), __VA_ARGS__)
since you didn't say that you have vprintf or something like it. If you do have something like it, you could wrap it in a function like Sergey L has provided in his answer.
The above TM_PRINTF does not work with an empty VA_ARGS list.
At least in GCC it is possible to write:
#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
The two ## signs remove the excess comma in front of them them if __VA_ARGS__ is empty.
If you can live with having to wrap the call in two parentheses, you can do it like this:
#define THAT_MACRO(pargs) printf pargs
Then use it:
THAT_MACRO(("This is a string: %s\n", "foo"));
^
|
OMG
This works since from the preprocessor's point of view, the entire list of arguments becomes one macro argument, which is substituted with the parenthesis.
This is better than just plain doing
#define THAT_MACRO printf
Since it allows you to define it out:
#define THAT_MACRO(pargs) /* nothing */
This will "eat up" the macro arguments, they will never be part of the compiled code.
UPDATE Of course in C99 this technique is obsolete, just use a variadic macro and be happy.
#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
The ## token will enable the usage TM_PRINTF("aaa");
#define PRINTF(...) printf(__VA_ARGS__)
This works like this:
It defines the parameterized macro PRINTF to accept (up to) infinite arguments, then preprocesses it from PRINTF(...) to printf(__VA_ARGS__). __VA_ARGS__ is used in parameterized macro definitions to denote the arguments given ('cause you can't name infinite arguments, can you?).
Limited library? Embedded system? Need as much performance as possible? No problem!
As demonstrated in this answer to this question, you can use assembly language to wrap function which do not accept VA_LIST into ones that do, implementing your own vprintf at little cost!
While this will work, and almost certainly result in the performance as well as abstraction you want, I would just recommend you get a more feature filled standard library, perhaps by slicing parts of uClibc. Such a solution is surely to be a more portable and overall more useful answer than using assembly, unless you absolutely need every cycle.
That's why such projects exist, after all.
This is a slightly modified version of #ldav1's excellent answer which prints time before the log:
#define TM_PRINTF(f_, ...) \
{ \
struct tm _tm123_; \
struct timeval _xxtv123_; \
gettimeofday(&_xxtv123_, NULL); \
localtime_r(&_xxtv123_.tv_sec, &_tm123_); \
printf("%2d:%2d:%2d.%d\t", _tm123_.tm_hour, _tm123_.tm_min, _tm123_.tm_sec, _xxtv123_.tv_usec); \
printf((f_), ##__VA_ARGS__); \
};
Below is an example wrapper for the vsprintf() function, from https://www.cplusplus.com/reference/cstdio/vsprintf/:
#include <stdio.h>
#include <stdarg.h>
void PrintFError ( const char * format, ... )
{
char buffer[256];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
perror (buffer);
va_end (args);
}
Following the example above, one can implement wrappers for other desired functions from <stdio.h>.
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.
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.