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

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)

Related

C: Is there a way to define a macro AND output some code in a single statement?

I would like to define a macro that would generate program text for me AND also set some non-string macro value. I know that including #define in another #define is not going to work so I'm trying to find a different way.
A simple example:
#include <stdio.h>
#define START_SYNTHETIC int SYNTHETIC_FUNCTION() {
#define END_SYNTHETIC return 0;}
#define SYNTHETIC_FUNCTION my_function
START_SYNTHETIC
printf("Hello from %s", "SYNTHETIC_FUNCTION");
END_SYNTHETIC
int main() {
my_function();
}
This code kinda works, it produces the following output:
Hello from SYNTHETIC_FUNCTION
There are two problems with it:
function name is not expanded and I just have "SYNTHETIC_FUNCTION" in the output. This is currently not critical but might be needed later on.
I dislike having three lines to start my synthetic function. The empty line inserted by autoformatter is especially irritating. Can I reduce this to just a single macro invocation?
Is there a way to define a macro AND output some code in a single statement?
No, in C macros can't define other macros.
function name is not expanded and I just have "SYNTHETIC_FUNCTION" in the output.
Sure it doesn't - it's inside a string literal. Macro replacement is not done inside a string literal.
Can I reduce this to just a single macro invocation?
I do not understand the point at all of this code. Just use __func__.
int my_function(void) {
printf("Hello from %s\n", __func__);
return 0;
}
or pass the name as a macro parameter:
#define SYNTHETIC(name) \
int name(void) { \
printf("Hello from %s\n", #name); \
printf("but really, just use __func__ anyway...: %s\n", __func__); \
return 0; \
}
SYNTHETIC(my_function)

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!")

Debug print by macro with variable names

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

c Macro with multiple optional arguments

I'm trying to write a debug print macro that will print the function name with the option of including format/varargs to print the parameters as well.
I've set up my modules so that each has it's on print color by adding a style variable to the individual modules and using it in my print macro.
The working print macro is as follows
//myprint.h
...
#define STYLE_UNDERLINE "\033[4m"
#define STYLE_NORMAL "\033[0m"
#define STYLE_BLUE "\033[0;34m"
... // more colo(u)rs here
#define PRINTF(fmt, ...) printf("%s" fmt STYLE_NORMAL, style, ##__VA_ARGS__)
...
Usage:
//myfile.c
...
static char * style = STYLE_BLUE;
void myFunc(int i) {
PRINTF("String with no params\n");
PRINTF("i value %d\n", i);
}
I'd like to do something similar with a PRINT_FN macro that would be used as follows
//myfile.c
...
void myFunc(int i) {
PRINT_FN(); // just print the function name
// equivalent to
PRINTF("%s%s()", STYLE_UNDERLINE, __func__);
PRINT_FN("%d", i) // print the function name and parameter
// equivalent to
PRINTF("%s%s(%d)", STYLE_UNDERLINE, __func__, i);
}
I can figure out a macro that almost accomplishes this, the problem being that it requires you to minimally send an empty format string.
#define PRINT_FN(fmt, ...) printf("%s" STYLE_UNDERLINE "%s(" fmt ")" STYLE_NORMAL, \
style, __func__, ##__VA_ARGS__)
Is there a way I can also make the fmt parameter optional?
Don't try to cram everything into one printf. Separate the adornments and the actual output:
#define PRINT_FN(...) \
do { \
printf("%s%s: ", STYLE_UNDERLINE, __func__); \
printf("" __VA_ARGS__); \
printf("%s\n", STYLE_NORMAL); \
} while (0)
Concatenating an empty string leads to an empty string if the format is empty or to the original format otherwise. gcc's -Wall setting warns about an empty format string, however.
The do ... while shold be compiled away and serves to make the macro behave as one statement. Maybe overkill in yor case, but still.

Detecting null parameter in preprocessor macro

I have the following macro function in vanilla C:
#define GLOG(format_string, ...) { \
const char *file = strrchr(__FILE__, '/'); \
char format[256] = "%s:%s!%d\t"; \
strncat(format, format_string, 248); \
strcat(format, "\n"); \
printf(format, __FUNCTION__, file ? file : __FILE__, __LINE__, ##__VA_ARGS__); \
}
which lets me print a debug message containing the current function, file and line number, e.g.
GLOG("count=%d", count);
might print
do_count:counter.c!123 count=456
How can I modify the function to print all local variables if caller omits format_string? e.g.
GLOG();
might print
do_count:counter.c!123 count=456, message="Hello world", array=[7, 8] structure={ptr=0xACE0FBA5E, coord={x=9, y=0}}
If that's not possible, how can I modify it to print just the current function, file and line number? e.g.
do_count:counter.c!123
As is, this returns an error:
error: expected expression before ‘,’ token
as the strncat line is simply
strncat(format, , 248);
First, inspecting all the local variables at runtime by the process itself seems impossible because C doesn't have any means for reflection.
Second, you would be much better off if you wrote the logging macro like that:
#include <stdio.h>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define GLOGF(fmt, ...) \
printf("%s:%s " fmt "\n", __func__, __FILE__ "!" TOSTRING(__LINE__), ##__VA_ARGS__)
int main (void) {
/* main:test.c!xx count=5 */
GLOGF("count=%d", 5);
/* main:test.c!xx */
GLOGF();
return 0;
}
It is simpler and doesn't incur any additional runtime overhead since the string is concatenated at compile-time.
Also note that I have used __func__ instead of __FUNCTION__, because the latter is non-standard.
I found this link in this answer. It might help you with the first part of the question.
The second, how to get all local variables, is much harder, if not impossible. The reason is that the code, when compiled, doesn't actually have variables, it just have offsets into a memory area (the stack.) It might be possible that your compiler have internal functions that can be used to inspect the stack, but then you only have possible values not the names of the variables. The only solution I see it to use special pre-processor macros to declare local variables, and then a list of structures to represent them for introspection, which will be a lot of both runtime and memory overhead.
As others here have mentioned, C does not have reflection features, and therefore you are not going to be capable of capturing the local variables in a macro call. That being said, if you want something to conditionally happen with a macro depending on if there are or are not any arguments to the macro invocation (i.e., your "non-null" and "null" arguments), then you can do something like the following:
#include <string.h>
#define NULL_IDENT ""
#define IDENT(ident_name) #ident_name
#define MACRO(ident_name) \
if (strcmp(NULL_IDENT, IDENT(ident_name)) == 0) { \
/* add code for a null argument passed to the macro */ } \
else { \
/* add code for a non-null argument passed to the macro */ }
Based on Blagovest Buyukliev's answer, I've come up with the following solution for part 2:
#define GLOG(fmt, ...) do { const char *fn = strrchr(__FILE__, '/'); \
printf("%s:%s!%d\t"fmt"\n",__func__,fn?++fn:__FILE__,__LINE__,##__VA_ARGS__);\
} while(0)
using the preprocessor's string concatenation to simply concatenate a null string if the parameter is omitted.
Additionally, I added the do {...} while(0) to swallow the trailing semicolon so that the following if...else works:
if (...)
GLOG();
else
/* do something else */
(idea from http://gcc.gnu.org/onlinedocs/cpp/Swallowing-the-Semicolon.html ).

Resources