Programming with verbose option in C - c

Does someone know how to write a program in C with the verbose option (the option to choose if messages are printed or not) in a nice way.
I mean, not writing an if(verbose) for each printf in the code.
Is there a more elegant solution?

Just use a (variadic) macro / vararg function that tests a flag before calling something like vfprintf.
/* Crude example. */
void my_log(char *format, ...)
{
va_list args;
if (!ok_to_log)
return;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
EDIT As requested
How about a slightly modified gnu example:
#define eprintf(format, ...) do { \
if (ok_to_print) \
fprintf(stderr, format, ##__VA_ARGS__); \
} while(0)

Make an array of function pointers
print_function_type fx[2] = {quietprint, verboseprint};
and instead of using an if when printing, use the correct element of the array
// if verbosemode is 0 call quietprint
// if verbosemode is 1 call verboseprint
fx[verbosemode]("%d", foo);

You can write your own printf-like function that checks for the verbose flag and then calls printf, if necessary.

Related

C: passing arguments from variadic function to variadic macro

I have a standard logging API built into my C code, a nice simple logF(const char *pFormat, ...) thing which has always, so far, been mapped to vprintf(), i.e.:
void logF(const char *pFormat, ...)
{
va_list args;
va_start(args, pFormat);
vprintf(pFormat, args);
va_end(args);
}
The C code above this API must work on multiple embedded platforms. I've just reached a platform (Nordic NRF52840) where the underlying logging interface I have to work with is presented as a variadic macro of the form NRF_LOG_INFO(...).
QUESTION: how do I correctly pass fn(const char *pFormat, ...) into a BLAH(...) macro? My brain hurts....
This is with GCC 4.9.3, though it would be nice to have a solution that is relatively relaxed about C compiler version.
EDIT 1: noted that I could redefine my logF() function to be a variadic macro and map it there, the issue is that I would then have a platform-specific header file rather than a generic one, I would have to move it down into the platform code and have one for each. Not impossible but more messy.
EDIT 2: I was asked for the trail of how NRF_LOG_INFO() expands. Here's the relevant output of the pre-processor:
#define NRF_LOG_INFO(...) NRF_LOG_INTERNAL_INFO( __VA_ARGS__)
#define NRF_LOG_INTERNAL_INFO(...) NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_INFO, NRF_LOG_SEVERITY_INFO, __VA_ARGS__)
#define NRF_LOG_INTERNAL_MODULE(level,level_id,...) if (NRF_LOG_ENABLED && (NRF_LOG_LEVEL >= level) && (level <= NRF_LOG_DEFAULT_LEVEL)) { if (NRF_LOG_FILTER >= level) { LOG_INTERNAL(LOG_SEVERITY_MOD_ID(level_id), __VA_ARGS__); } }
#define LOG_INTERNAL(type,...) LOG_INTERNAL_X(NUM_VA_ARGS_LESS_1( __VA_ARGS__), type, __VA_ARGS__)
#define LOG_INTERNAL_X(N,...) CONCAT_2(LOG_INTERNAL_, N) (__VA_ARGS__)
Then depending on number of args, anything up to:
#define LOG_INTERNAL_6(type,str,arg0,arg1,arg2,arg3,arg4,arg5) nrf_log_frontend_std_6(type, str, (uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2), (uint32_t)(arg3), (uint32_t)(arg4), (uint32_t)(arg5))
void nrf_log_frontend_std_6(uint32_t severity_mid,
char const * const p_str,
uint32_t val0,
uint32_t val1,
uint32_t val2,
uint32_t val3,
uint32_t val4,
uint32_t val5);
It is not possible to pass the arguments from a variadic function to a variadic macro.
As you want to hide the platform specific macro call from the API header you can process the function arguments with vsnprintf instead of vprintf and call the logging macro with format "%s" and the resulting string buffer.
void logF(const char *pFormat, ...)
{
va_list args;
/* Choose a reasonable size or replace with dynamic allocation based on the return value of vsnprintf */
/* This could also be a static variable or a global variable to avoid allocation of a big buffer on the stack. */
char buffer[1024];
va_start(args, pFormat);
vsnprintf(buffer, sizeof(buffer), pFormat, args);
NRF_LOG_INFO("%s", buffer);
va_end(args);
}
Note that you may have to call NRF_LOG_FLUSH before the buffer goes out of scope or gets overwritten. See https://devzone.nordicsemi.com/f/nordic-q-a/22647/nrf_log_info-how-to-print-log-with-string-parameter

String handling inside Preprocessor macro

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.

How to wrap printf() into a function or macro?

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>.

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.

How to convert a variable argument function into a macro?

I have a variable argument function which prints error messages in my application, whose code is given below:
void error(char *format,...)
{ va_list args;
printf("Error: ");
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
printf("\n");
abort();
}
This function is used in error conditions as follows:
error("invalid image width %d and image height %d in GIF file %s",wid,hei,name);
The error() function is called from different places with different arguments (variable argument function).
The function approach works fine.
Now, if I have to convert this function into a macro, how do I do it? I tried doing it as:
#define error(format) {va_list args;\
printf("Error: ");\
va_start(args, format);\
vfprintf(stderr, format, args);\
va_end(args);\
printf("\n"); abort()}
But this does not print the arguments correctly.
What is wrong in the macro definition above?
What is the fix?
If your compiler supports ISO style variadic macros, you can define a macro as such:
#define error(...) \
fprintf(stderr, "Error: "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
abort();
Alternatively, if you are using GCC, there's also the GNU style variadic macro used as such:
#define error(format, args...) \
fprintf(stderr, "Error: "); \
fprintf(stderr, format , ## args); \
fprintf(stderr, "\n"); \
abort();
For more information, see http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
Update
If your compiler does not have variadic macro support, a (poor?) alternative would be to stick to the va_list in function approach. If you wish the definition to reside in a header file, then perhaps a static inline function?
static inline void error(const char *fmt, ...) {
#define PRINT_ERROR
va_list args;
fprintf(stderr, "Error: ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
abort();
#endif
}
Here is an article with some examples on variable arguments used in a macro. It looks like it should do what you're looking for. You can use __VA_ARGS__ in your macro.
Which compiler are you using?
Macros do not (yet?) support variadic arguments and anyway, using va_list wouldn't work here, it only works on variadic function arguments.
Why do you want to replace the function (which works fine, according to you) with a macro anyway?
There's a common extension that does what you want, simply write:
#define error(args...) (fputs("Error: ",stdout),printf(args),puts(""))
C99 users can also say:
#define error(...) (fputs("Error: ",stdout),printf(__VA_ARGS__),puts(""))
but there are some problems with using __VA_ARGS__. Fortunately there's a GCC extension to deal with it, but then you're back to using a compiler-specific extension, and the args... mode is more widely available.
Many compilers support GNU style variadic macros, like this:
#define error(format,args...) do { \
fprintf(stderr, "error: " format "\n", ##args); \
abort(); \
} while(0)
However, if you aim for portability, do not use variadic macros.

Resources