Debug print by macro with variable names - c

Is there a way, how to neatly pass variable name and its value to a debug macro? What I'm using now is "just" this.
#if DEBUG_LEVEL >= 1
#define DEBUG_PRINT(fmt, ...) do{\
fprintf(stderr, ANSI_COLOR_YELLOW "[DEBUG]: %s:%c\t", __FILE__, __LINE__);\
fprintf(stderr, fmt ANSI_COLOR_RESET, __VA_ARGS__);}while(0)
#else
#define DEBUG_PRINT(...)
#endif
#define STR(x) #x
It's by all means fine, but when I want to output what variable belongs to which name, I use construct like this and it easily gets too cumbersome.
DEBUG_PRINT(STR(min_a)": %u\t"STR(max_a)": %u\t"STR(min_c)": %u\t"STR(max_c)":%u\t"STR(min_m)": %u\t"STR(max_m)":%u\t"STR(d)": %d\n", min_a, max_a, min_c, max_c, min_m, max_m, d);
Is there a way, how to get rid of those STR(x) in DEBUG_PRINT in such a way, that variable name stays visible and the overall formatting stays pretty much the same? I don't mind putting in the format specifiers, though my first thought was to get rid of those as well, if possible. The most important thing is to retain variable number of arguments.
So my question is, how to write a macro, that do this "pretty printing", without the need to call STR(x) - something like this: DEBUG_PRINT_VARS(min_a, max_a, min_c, max_c, min_m, max_m, d)

Well, I sort of solved it for now by using MAP macro (https://github.com/swansontec/map-macro), edited it for allowing two argument function, and then having:
#if DEBUG_LEVEL >= 1
#define DEBUG_PRINT(...) do{\
fprintf(stderr, ANSI_COLOR_YELLOW "[DEBUG]: %s:%d\t", __FILE__, __LINE__);\
MAP(PRINT_ARG, __VA_ARGS__); \
fprintf(stderr, "\n" ANSI_COLOR_RESET);}while(0)
#else
#define DEBUG_PRINT(...)
#endif
#define PRINT_ARG(x, y) fprintf(stderr, #x": "y"\t", x);
and using it like this
DEBUG_PRINT(min_a, "%u", max_a, "%u", min_c, "%u", max_c, "%u", min_m, "%u", max_m, "%u", d, "%d");
It answers the question itself, so that's the reason why am I posting it as an answer, though I'd be really interested in finding out a way, how to produce conversion specifiers implicitly

Related

Multiline macro in c (#if-#endif)

my code:
#define DEBUG 3
#define TEST(...)
#if (DEBUG == 3) \
printf("%s: %s\n", __FILE__, __VA_ARGS__);
#endif
int main(void) {
TEST("TEST")
return 0;
}
Error: missing the binary operator before token 'printf'.
I don't understand what's the problem
You're trying to put the #if inside the macro, but C doesn't permit that kind of thing. The reason it's failing is the printf inside the #if is unexpected. This is a common request, but it's just not allowed.
However, you can accomplish the same thing by changing the way you do the test:
#include <stdio.h>
#define DEBUG 3
#if (DEBUG == 3)
# define TEST(...) printf("%s: %s\n", __FILE__, __VA_ARGS__);
#else
# define TEST(...)
#endif
int main(void) {
TEST("TEST")
return 0;
}
EDIT: Though test-type macros like this are common, this is not a great way to do it because it can lead to unhappy surprises in debug/nondebug situations.
What happens in this case?
if (something)
TEST("blah")
else
TEST("no")
This works as you expect in debug mode, but won't even compile in production because it devolves to if (something) else - it doesn't even have a closing semicolon. It's easy to find other examples that are much more devious.
Hiding a semicolon inside a macro like this is usually asking for trouble, so the better approach is to make them function-like where you have to provide the semicolon yourself, and the most obvious way to do it is:
# #define TEST(...) printf("%s: %s\n", __FILE__, __VA_ARGS__) // no semicolon
...
if (something)
TEST("blah");
else
TEST("no");
This is better and leads to less surprises, but it's still a little troublesome in that it can leave a dangling semicolon lying around, which some compilers object to.
A fix for this can be:
#if (DEBUG == 3)
# define TEST(...) printf("%s: %s\n", __FILE__, __VA_ARGS__)
#else
# define TEST(...) ((void)0) // dummy statement
#endif
which at least quiets the compiler. There are other approaches here too.
In C #define cannot "contain" #ifs

How to write a macro with optional and variadic arguments

I have a macro called PRINT(...) that I use in my code, which gets a variable number of arguments and acts like printf (gets a format and arguments). It's defined like this:
#define PRINT(...) PRINT(__VA_ARGS__)
Now I want to modify it so it will have an optional argument, say that its name is number and it will add a numeric prefix to the printing. For example:
PRINT("%s", "hi") -> will print hi
PRINT(1, "%s", "hi") -> will print 1: hi
How can I change the PRINT macro to support this?
Important to say, that I don't want to change any existing call to this macro from my code (in the example, if I have a call to PRINT("%s", "hi") - it needs to remain the same after the change).
Also, I can't create new macro for this purpose- must use the existing PRINT macro for this purpose (but off course I can change it's arguemnts definition).
Any idea how can I do this?
Edit: I saw this post about variadic macro- but It's different from what I'm asking here since the argument number needs to be a recognized variable, which will be treated in the implementation of PRINT as -1 if the call to PRINT doesn't contain the number argument (-1 will be an indicator for printing no number) and otherwise it will print the number prefix.
As of C11, you can use the _Generic keyword. This allows you to check the type of any value or variable. According to this document, _Generic has behaviour that varies between compilers. This answer provides a simple solution, though, using the comma operator.
#define PRINT(fst, ...) \
( \
_Generic((0, fst), char *: 1, default: 0) ? \
PRINTNL(fst, __VA_ARGS__) : \
PRINTL(fst, __VA_ARGS__) \
)
Where PRINTNL prints without the number and PRINTL prints with the number.
Rest of the code:
#define PRINTNL(...) printf(__VA_ARGS__)
#define PRINTL (n, ...) ({ \
printf("%d: ", n); \
printf(__VA_ARGS__); \
})
Since you'd know by the time of writing whether the first argument is a number prefix or not, make a macro by another name for prefixing with the number. Here I assume that PRINT(...) expands to printf(__VA_ARGS__):
#define PRINT(...) printf(__VA_ARGS__)
So define a macro NPRINT that calls printf twice, once to output the prefix with number and once with the format:
#define NPRINT(number, fmt, ...) (printf("%d: ", number), printf(fmt, __VA_ARGS__))
Usage
#include <stdio.h>
int main(void) {
NPRINT(1, "%s\n", "hi");
}
Of course this doesn't work if the call to printf was supposed to be atomic - now if the format string was always a literal string, then you could use string concatenation:
#define NPRINT(number, fmt, ...) (printf("%d " fmt, number, __VA_ARGS__))
If it can be a variable and only one call to PRINT is allowed, the only portable way that I could see is to make a function that builds the format.
With the latest edit that without the number argument, -1: should be prefixed, this would simply become:
#define PRINT(...) NPRINT(-1, __VA_ARGS__)
Please have a look at the ##__VA_ARGS__ macro. Also check the code below written for a log function.
In the header file
/**
* ##__VA_ARGS__ allows us to make varadic arguments optional
* https://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html
* also check __VA_OPT__ (C++20)
*/
#define APP_LOG(message, ...) \
do { \
APP_LOGX( __FILE__, __LINE__, ("\e[1;34m[INFO]: \e[0m" message), ##__VA_ARGS__); /** BLUE */ \
} \
while(0)
#define APP_ERROR(message, ...) \
do { \
APP_LOGX( __FILE__, __LINE__, ("\e[1;31m[FATAL]: \e[0m" message), ##__VA_ARGS__); /** RED */ \
} \
while(0)
In the implementation
/** #include <libgen.h> */
void APP_LOGX(const char * file, int num, const char* message, ...)
{
va_list ap;
int length;
char * tfilename = NULL;
tfilename = strdup(file);
length = strlen(message);
if(length>0){
va_start(ap, message);
vprintf(message, ap);
printf(" | File: %s Line %d ", basename(tfilename), num);
va_end(ap);
/* add newline if nessasary */
if(message[length -1] != '\n'){
printf("\n");
}
}
free(tfilename);
}
Application
APP_LOG("app display init")
or
APP_LOG("Value of x acceleration %.2f", g);
APP_ERROR("Something bad happened!")

How to modify the argument of a multi-argument macro?

I have various kinds of printf macros in my code defined along those lines:
#define DEBUG(...) printf(__VA_ARGS__)
This works well:
DEBUG("Hello %d",1);
will be the same as
printf("Hello %d",1);
Now can I make my macro also edit the args that are passed in to, say, add a \n at the end of the first argument? I.e. so that
DEBUG("Hello %d",1);
turns into
printf("Hello %d\n",1);
I suggest using:
#define DEBUG(fmt, ...) printf(fmt "\n", __VA_ARGS__)
The drawback is that you have to have at least one non-format string argument, i.e. you cannot use the macro as:
DEBUG("foo");
anymore.
For some compilers there are work-arounds allowing empty __VA_ARGS__ like
#define DEBUG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
in gcc (thanks to M. Oehm).
If you want your \n to be always on the final, you can just add one more printf statement:
#define DEBUG(...) printf(__VA_ARGS__); printf("\n")
...
DEBUG("hello %d", 1);
DEBUG("hello %d", 1);
Outputs:
hello 1
hello 1
As pointed out by the others, this won't work as expected with this scenario:
if (cond)
DEBUG("Blah")
So you will have to define the macro this way:
#define DEBUG(...) do { printf(__VA_ARGS__); printf("\n"); } while(0)
Thanks to M. Oehm and undur_gongor
You could do this with string literal concatenation, if you know that the first argument is always a string literal.
If you have a macro
#define EXAMPLE(A,B) \
printf("%s", A B)
then in code
EXAMPLE("foo ", "bar\n");
would be the same as
printf("%s", "foo bar\n");
(Since you didn't show full code, I assume you can adapt this to your case)

is there a non-fatal equivalent to assert in c?

I would like to write assert statement but not abort the program. So perhaps use exact same syntax as assert() but called expect(). Of course I can write my own, but assert is quite clever (e.g. it knows not only the file and line number but even the expression which is not TRUE).
I could of course dig into the library and C-v/C-c a solution.
But this is such an obvious generic request I can't believe there is not a good solution already. Which should of course be easily found here...
It's because assert is a preprocessor macro, and so can use the __LINE__ and __FILE__ macros as the whole macro invocation is expanded into a single line.
You can easily make your own:
#define expect(value, message) \
do \
{ \
if (!(value)) \
{ \
fprintf(stderr, "%s failed in %s:%d\n", #value, __FILE__, __LINE__); \
} \
} while(0)
No, there are no such thing. However, it is quite easy to write it as :
#define expect( chk ) \
if (!(chk)) \
printf("Assertion (%s) failed %s at line %d ", #chk, __FILE__,__LINE__);
This test :
int main()
{
expect(0);
expect(1);
return 0;
}
is going to print the first failed assertion :
Assertion (0) failed t.c at line 8
Live demo.
With credit to BЈовић
#ifdef NDEBUG
#define expect(chk) ((void *)0)
#else
#define expect(chk) (chk ? (void) (0) : fprintf(stderr,"%s:%d %s: expectation (%s) failed.\n", __FILE__ , __LINE__ , __func__ , #chk))
#endif
This version
writes to stderr, not stdout
can be disabled like assert() with the NDEBUG macro
It looks as much like the assert() message as possible, though of course it doesn't have the flexibility that assert does in terms of other parameters.
I didn't see why forcing the use of a semicolon is useful - since if there is one it works, and if there isn't it still works!
Some cleverer solution like try...catch around assert() was my hoped for answer, though!

turning off DEBUG macros for a specific function (NDEBUG)

I am using the following macro for printing debug information that I found on the web. It works great.
However, I would like to turn-off debug printing for function A when debugging function B, which calls function A. I tried #define NDEBUG function A #undef NDEBUG but haven't managed to suppress printing in function A.
Any help will be greatly appreciated.
Any suggestions for alternative ways of accomplishing the task is also welcome.
Thanks ~RT
#ifdef NDEBUG
/*
If not debugging, DEBUGPRINT NOTHING.
*/
#define DEBUGPRINT2(...)
#define DEBUGPRINT(_fmt,G ...)
#else
/*
Debugging enabled:
*/
#define WHERESTR "[file %s, line %d]: "
#define WHEREARG __FILE__, __LINE__
#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
#endif /* NDEBUG */
maybe you should wrap the trace into a module so that you can turn on/off the tracing dynamically in run-time and in that way you can specifically turn it off for a function call. In release mode you could replace all tracing with empty statements although in my experience I find it good to keep tracing in release mode as well - just in case.
NDEBUG is useful at the time assert.h is included, so #define NDEBUG/#undef NDEBUG later will not do anything.
You can do something like this though:
#if defined(NDEBUG) || !defined(MY_DEBUG)
/*
If not debugging, DEBUGPRINT NOTHING.
*/
#define DEBUGPRINT2(...)
#define DEBUGPRINT(_fmt,G ...)
#else
/*
Debugging enabled:
*/
#define WHERESTR "[file %s, line %d]: "
#define WHEREARG __FILE__, __LINE__
#define DEBUGPRINT2(...) fprintf(stderr, __VA_ARGS__)
#define DEBUGPRINT(_fmt, ...) DEBUGPRINT2(WHERESTR _fmt, WHEREARG, __VA_ARGS__)
#endif /* NDEBUG */
Then, in function A():
...
#undef MY_DEBUG
result = B();
#define MY_DEBUG
...
This will debug B() when it's called from anywhere except from A(). To get debugging, you will need MY_DEBUG to be defined and NDEBUG to be undefined.
Edit: You will need to define MY_DEBUG when you want to compile with debugging, but hopefully you're using make or some other build tool, so this should be easy.

Resources