C macro that voids variable length input arguments - c

Is there a way to define a macro that voids variable list of arguments?
#define VOID_ARGS(...) ((void)##__VA_ARGS__)
The use case is void arguments to suppress compiler error [-Werror=unused-value] when warnings treated as errors:
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) VOID_ARGS(fmt, ##__VA_ARGS__)
#endif

Does this give you an idea how to solve that problem?
debug.h:
extern int dbg_func(const char *format, ...);
//Does nothing
extern int ignoreDebug(const char *format, ...);
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) ignoreDebug(fmt, ##__VA_ARGS__)
#endif
debug.c:
int ignoreDebug(const char *format, ...)
{
(void)format;
return 0;
}
int dbg_func(const char *format, ...)
{
TODO: Some code needs to go here.
return 0;
}

Rather than attempting to put the debug logic in the function declaration, add it to the function body instead:
int dbg_func(const char *format, ...)
{
#ifdef DEBUG
// normal debug logic
#else
(void)format;
return 0;
#endif
}

I found a way only using the processor. The idea came from this answer https://stackoverflow.com/a/11763277/6082851 The idea is to define a bunch of macros that void the arguments, one macro per possible number of arguments. With the use of __VA_ARGS__, the correct macro can be chosen depending on the number of arguments. Sadly, i didn't found a way to make it recursive so that a limited number of macros can be used for an arbitrary number of arguments, the only way i found was to define a macro for each possible number of arguments. But it can be expanded to an arbitrary amount.
#include <stdio.h>
#ifndef DEBUG
#define DEBUG 1
#endif
#if DEBUG
#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
//GET_MACRO will get the 6. argument
#define GET_MACRO(a,b,c,d,e,f,...) f
//Macros that void a number of arguments
#define SET_VOID0()
#define SET_VOID1(a) (void)a;
#define SET_VOID2(a,b) (void)a;(void)b;
#define SET_VOID3(a,b,c) (void)a;(void)b;(void)c;
#define SET_VOID4(a,b,c,d) (void)a;(void)b;(void)c;(void)d;
#define SET_VOID5(a,b,c,d,e) (void)a;(void)b;(void)c;(void)d;(void)e;
//Void all arguments to avoid compiler warnings.
//SET_VOID5 is used when there are 5 arguments used, SET_VOID4 when 4 are used, ...
#define DEBUG_PRINT(...) GET_MACRO(__VA_ARGS__, SET_VOID5, SET_VOID4, SET_VOID3, SET_VOID2, SET_VOID1, SET_VOID0)(__VA_ARGS__)
#endif
int main(void)
{
int foo=5;
int bar=3;
DEBUG_PRINT("Foo %i Bar %i\n",foo,bar);
return 0;
}

Related

Using macro statement in macro function in C

Using #ifdef <macro> <statement> #endif allows one to have verbose messages displayed only during development and is quite handy. I wonder if something like the code below is possible, becoming even shorter:
// pseudo-code:
#define IN_DEV
#define DEBUG_ONLY(statement) (#ifdef IN_DEV (statement) #endif)
int main(void)
{
DEBUG_ONLY(printf("hello from debug mode\n");)
//...
}
This would only cost me a very readable one-liner which can be turned on or off. Is something like this / close to this possible?
You could change the meaning of DEBUG_ONLY dependent on if IN_DEV is defined:
// pseudo-code:
#ifdef IN_DEV
#define DEBUG_ONLY(statement) {statement}
#else
#define DEBUG_ONLY(statement) // Nothing
#endif
int main(void)
{
DEBUG_ONLY(printf("hello from debug mode\n");)
//...
}
Running example: Link
It doesn't make much sense to pass whole expressions as parameters to macros. That is both dangerous and unmaintainable. Worse yet, it's taking us down the obfuscation road of "lets invent our own private macro language instead of using readable C that anyone can understand". That's a terrible idea even for debugging purposes.
The more sensible approach would be a function-like printing macro which only prints something in debug build.
#ifdef INDEV
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#endif
int main(void)
{
DEBUG_PRINT("hello from debug mode\n");
}
Optionally this macro can be narrowed down to only accept strings and be made more type safe (C17 only):
#ifdef INDEV
#define DEBUG_PRINT(str) _Generic((str), char*: puts(str))
#else
#define DEBUG_PRINT(str) _Generic((str), char*: (void)0)
#endif
That is not possible. You cannot use #if inside a macro definition.
What you can do is this:
#define IN_DEV
#ifdef
#define DEBUG_ONLY(statement) (statement)
#else
#define DEBUG_ONLY(statement)
#endif
int main(void)
{
DEBUG_ONLY(printf("hello from debug mode\n");)
//...
}
This is also switchable with only a single macro IN_DEV.

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.

Use multiple macros in a macro definition

I'm trying to use multiple macros in the definition of another macro, but seem to have problems concatenating them together. Here's a very simplified version of what I'm trying to do:
#include <stdio.h>
#define PICK_SET_A
#ifdef PICK_SET_A
#define SET A
#endif
#ifdef PICK_SET_B
#define SET B
#endif
#define ENABLE_VAR_1_A 1
#define ENABLE_VAR_2_A 1
#define ENABLE_VAR_1_B 0
#define ENABLE_VAR_2_B 0
#define MACRO_RESOLVE(var,set) ENABLE_VAR_##var##_##set
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
#define ENABLE_VAR_2 MACRO_RESOLVE(2, SET)
int main(int argc, char **argv) {
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
return 0;
}
I would expect the result to be 0.
However, I'm getting compile errors because the MACRO_RESOLVE macro isn't resolving the way I expect it to:
$ gcc -o asdf asdf.c
asdf.c:25:36: error: use of undeclared identifier 'ENABLE_VAR_1_SET'
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
^
asdf.c:20:26: note: expanded from macro 'ENABLE_VAR_1'
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
^
asdf.c:18:32: note: expanded from macro 'MACRO_RESOLVE'
#define MACRO_RESOLVE(var,set) ENABLE_VAR_##var##_##set
^
<scratch space>:229:1: note: expanded from here
ENABLE_VAR_1_SET
^
1 error generated.
So it looks like SET isn't getting expanded when I define ENABLE_VAR_1.
Since you are trying to build a macro name, you need to do enough intermediate expansions along the way for all tokens to expand. See it live here.
#include <stdio.h>
#define PICK_SET_A
#ifdef PICK_SET_A
#define SET A
#endif
#ifdef PICK_SET_B
#define SET B
#endif
#define ENABLE_VAR_1_A 1
#define ENABLE_VAR_2_A 1
#define ENABLE_VAR_1_B 0
#define ENABLE_VAR_2_B 0
#define MACRO_RESOLVE__(M) M
#define MACRO_RESOLVE_(V, S) MACRO_RESOLVE__(ENABLE_VAR_ ## V ##_## S)
#define MACRO_RESOLVE(var,set) MACRO_RESOLVE_(var, set)
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
#define ENABLE_VAR_2 MACRO_RESOLVE(2, SET)
int main(int argc, char **argv) {
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
return 0;
}

Using a macro for a function

I'm having the following problem with a macro for a function. This was working until I added the print_heavyhitters function. I have this in m61.h:
#if !M61_DISABLE
#define malloc(sz) m61_malloc((sz), __FILE__, __LINE__)
#define free(ptr) m61_free((ptr), __FILE__, __LINE__)
#define realloc(ptr, sz) m61_realloc((ptr), (sz), __FILE__, __LINE__)
#define calloc(nmemb, sz) m61_calloc((nmemb), (sz), __FILE__, __LINE__)
#define print_heavyhitters(sz) print_heavyhitters((sz), __FILE__, __LINE__)
#endif
in m61.c, all of these functions are fine except print_heavyhitters(sz). I get " - Macro usage error on the function print_heavyhitters:
- Macro usage error for macro:
print_heavyhitters
- Syntax error
m61.c:
#include "m61.h"
...
void *m61_malloc(size_t sz, const char *file, int line) {...}
void print_heavyhitters(size_t sz, const char *file, int line) {...}
You use the same name for the macro and the function it was intended to expand to.
Using the same name for the macro and for the function name is OK as far as the preprocessor is concerned, since it won't expand it recursively, but it can easily lead to confusing errors such as this. You can do this as long as you're careful to #undef it in the right places, but I'd recommend using a different symbol name to avoid confusion.
I'd do something like this:
// Header file
#if !M61_DISABLE
...
#define print_heavyhitters(sz) m61_print_heavyhitters((sz), __FILE__, __LINE__)
#endif
// Source file
#include "m61.h"
#if !M61_DISABLE
#undef print_heavyhitters
#endif
void print_heavyhitters(size_t sz)
{
// Normal implementation
}
void m61_print_heavyhitters(size_t sz, const char *file, int line)
{
// Debug implementation
}

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