How to set dynamically toggle defined macro? - c

Im trying to make my defines can be switched during runtime, so I cant enable/disable printing some info.
I have next files:
main.c
config.c
config.h (included in both c files)
in config.c :
//define DEBUG // <--------------- COMMENT THIS TO SWITCH PRINT/NOT PRINT
#define PRINTF(fmt, ...) printf("TAG: " fmt "\n", ## __VA_ARGS__)
#ifdef DEBUG
#define DPRINTF PRINTF
#else
#define DPRINTF(...) do {} while (0)
#endif
int foo()
{
...
if(error){
PRINTF("error happens, code %d", code);
}
else{
DPRINF("all good, all parameters: [%d][%d]", par1, par2);
}
}
(short explanation: if DEBUG defined then macro DPRINTF will print some info, otherwise do nothing)
What I want is be able to dynamically switch it from main.c somehow, instead of comment / uncomment and recompile program.
So my idea was to set in config.h
extern uint8_t dbg_status;
#define DGB_ON (1)
#define DGB_OFF (0)
#define ENABLE_DBG (dbg_status? (DGB_ON) : (DGB_OFF))
And in main.c do something like that:
uint8_t dbg_status;
int main(int argc, char** argv)
{
// enable debug if run with next argument:
// program.exe -DEBUG
if (!strcmp(argv[1], "-DEBUG"))
{
// enable debug prints
dbg_status= 1;
}
else
{
// disable debug prints
dbg_status= 0;
}
...
}
But Im stuck with it now, I dont know what to do next...
Add some additional defines in config.c?
#if (ENABLE_DEBUG)
#define DEBUG
#endif
I feel that Im on right way, but dont see where to move next.
UPD:
Original idea from here:
Changing a macro at runtime in C
But Im stuck with realization...

You could use something like this:
int debugflag = 0;
void DPRINTF(char *format, ...) {
if (!debugflag)
return;
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
Now you can choose dynamically with the global variable debugflag if you want the debug output or not.
With macros, this is not possible directly, since these are evaluated at compile time and cannot be influenced at runtime directly.

Related

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.

What is the standard way to log a program in C?

Programs in C that have --verbose or --debug option, how they actually implement it? Without using 3rd party libraries.
My goal is not to do this all the time:
if(debug) printf("Debug msg\n");
printf("Info msg\n");
The most common I've seen is to print to stderr.
#ifdef DEBUG
#define DEBUG_MESSAGE(fmt, ...) fprintf(stderr, fmt ## "\n", __VA_ARGS__)
#else
#define DEBUG_MESSAGE(fmt, ...)
#endif
Elsewhere...
DEBUG_MESSAGE("VERBOSE: %s", "This is a verbose message.");
EDIT
Something that would work at runtime:
#define DEBUG_MESSAGE(fmt, ...)\
do{\
if(g_debugEnabled) fprintf(stderr, fmt ## "\n", __VA_ARGS__);\
}while(0)
Which can be used similarly.
LAST EDIT
Changed to use arbitrary format string with __VA_ARGS__.
You can refer the below program where a macro is defined and based on the option passed to the executable logging is enabled.
#include <stdio.h>
#include <string.h>
#define STREQ(a, b) !(strcmp((a), (b)))
#define logmsg(fmt, ...) \
do { \
if (debug) \
printf(fmt, ##__VA_ARGS__);\
}while(0)
char debug;
int main(int argc, char *argv[])
{
if (argc > 1) {
if ( STREQ(argv[1], "debug"))
debug = 1;
}
logmsg("%s\n", "hello_world");
return 0;
}
Pass debug as the first argument to the executable to enable logging
Note : This program has been tested on Linux with gcc compiler

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.

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

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.

Help with my printf function

For debugging purposes I would like to have a printf_debug function that would function just like the standard printf function, but would only print if a #DEFINE DEBUG was true
I know I have to use varagrs (...) but I have no idea how to actually achieve that.
Thanks in advance.
Easier to just #define it away. Something like this:
#ifdef DEBUG
#define printf_debug printf
#else
#define printf_debug while(0)printf
#endif
I don't what exactly you want to achieve. In case you want a code block to execute only if DEBUG is defined, use the preprocessor directive #ifdef.
#include <stdio.h>
#include <stdarg.h>
#define DEBUG
void printf_debug(const char *format, ...) {
#ifdef DEBUG
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
#endif /* DEBUG */
}
You don't need to use vargs, macros will work. Here is an example, which will prints function and line number as well:
#ifdef DEBUG
#define printf_debug(fmt, args...) printf("%s[%d]: "fmt, __FUNCTION__, __LINE__, ##args)
#else
#define printf_debug(fmt, args...)
#endif
The ##args here will be replaced by the args list, which likes what vargs does in function call.
You have to use the va_arg macros, they are used to access the variadic variables. A useful link: http://www.cppreference.com/wiki/c/other/va_arg. The reference is for C++, but these macros can be used in C as well.
In your actual implementation you place the code using the variadic variables in a #ifdef block.
But if you're looking for a regular call to printf, dependent on DEBUG a simple #define acting as an alias will do.
C99 compiler only!
#include <stdio.h>
#define DEBUG
#ifdef DEBUG
#define debug(...) printf(__VA_ARGS__)
#else
#define debug while(0)
#endif
int main(int argc, char *argv[])
{
debug("Only shows when DEBUG is defined!\n");
return 0;
}
to be honest varidic macros are not needed you could just easily write it as this:
#include <stdio.h>
#define DEBUG
#ifdef DEBUG
#define debug printf
#else
#define debug while(0)
#endif
int main(int argc, char *argv[])
{
debug("Only shows when DEBUG is defined!\n");
return 0;
}
Thinking about it, debug information should go to stderr so as not to interfer with stdout, so this one should be favoured:
#include <stdio.h>
#define DEBUG
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug while(0)
#endif
int main(int argc, char *argv[])
{
debug("Only shows when DEBUG is defined!\n");
return 0;
}

Resources