C macro with special variable arguments - c

I always write below code for debug purpose:
printf("%s:%d this is a string %s int %d",__FUNCTION__,__LINE__,strval,intval);
Now since the first part (FUNCTION,LINE) is always used, so I wish to create a macro to do it and just append other debug strings.
Maybe looks like:
#define MYPRINT(args...) printf("%s:%d",__FUNCTION__,__LINE__);printf(##args)
But I wish to use one statement rather than two as above! Is it possible?
Clarify not duplicate of this one
This is different because I wish to add some new field into print command. actually answers here is great, thanks for all's help!

If you want a single call to printf(), your MYPRINT needs to be aware of a format string. You can try something like this, so long as the format string is a literal:
#define MYPRINT(FMT, ...) printf("%s:%d " FMT, __FUNCTION__, __LINE__, ##__VA_ARGS__)
The ## is a GCC (and perhaps others) compiler extension that swallows the comma in the case __VA_ARGS__ is actually empty. If your compiler does not support it, leave it off.

You can use a variadic macro and use , to have one statement:
#define MYPRINT(...) (printf("%s:%d",__FUNCTION__,__LINE__), printf(__VA_ARGS__))

How about this :
#include <stdio.h>
#define MYPRINT(fmt, ...) \
printf("[%s]:%d - " fmt "\n", __FUNCTION__, __LINE__, __VA_ARGS__)
int main() {
char const *s = "My string";
int i = 42;
MYPRINT("%s, %d", s, i);
}
Outputs :
[main]:8 - My string, 42

Related

Example of using the ## preprocessor operator

I know the following is a very trivial example, but how would I convert the following into a single function call that uses the preprocessor ## 'glue' operator?
void print_string(char *s)
{
printf("%s\n", s);
}
void print_num(int n)
{
printf("%d\n", n);
}
int main(void)
{
print_string("Hello");
print_num(5);
}
The only thing I can thing of (which doesn't really simplify anything) is:
#define PRINT(type) print_ ## type
PRINT(string)("Hello");
PRINT(num)(4);
Or, is there a better way to use that?
You can make the identification to be the first function argument:
#define PRINT(type, value) print_ ## type(value)
PRINT(string, "Hello");
PRINT(num, 4);
But I see no value in that over just writing printf, as someone will have to learn to write num in case of int, he might as well learn to use %d anyway:
printf("%s\n", "Hello");
printf("%d\n", 4);
Type dispatch is not possible in pre-processor - it's not aware of types. In C11 there's _Generic that allows compiler to choose different function depending on type:
#define PRINT(value) _Generic((value), \
char *: print_string, \
int: print_int)(value)
PRINT("Hello");
PRINT(4);
By overloading the macro on each argument and applying such _Generic macro on each argument it's possible to build a replacement for C++ std::cout. So a little self-promotion: that's a topic I explored in yio library that allows just to do:
yprint("Hello ", 4, "\n");

Insert double quotes in a macro for pragma in C

I'm trying to create a macro in C in order to create the correct pragma declaration.
_pragma(section .BLOCK1) //Correct but deprecated
_pragma(section ".BLOCK1") //Correct without warning
Following code is working, but the compiler gives me a warning (deprecated declaration):
#define DO_PRAGMA(x) _Pragma(#x)
#define PRAGMA(number) \
DO_PRAGMA(section .BLOCK##number)
PRAGMA(1)
How I can include the double quotes in the macro?
I have already tried inserting "\"", but it is not working because the string is interpreted directly.
You can pass this to a helper macro which expands and stringifies the arguments.
#define _stringify(_x) #_x
#define DO_PRAGMA(a) _Pragma(_stringify(a))
#define PRAGMA(number) \
DO_PRAGMA(section _stringify(.BLOCK##number))
The correct way to add double quotes to a macro is indeed to use backslash i.e.:
#define STRING "\"string\""
"string" is now stored in STRING.
To concatenate a number into your macro string you can do something like, but it needs to be stored in non const char array:
#define STRING "section \".BLOCK%d\""
#define CONV(str, n) sprintf(str, STRING, n)
//...
char str [50];
CONV(str, 1);
DO_PRAGMA(str);
//...
If you haven't already, check pragma documentation and this usage example.

Convert a macro into a function call

I have a created a macro which will print the timestamp with all the prints.
void timestamp()
{
struct timeval tv;
gettimeofday(&tv,NULL);
printf("%d",tv.tv_sec );
}
#define printf_all(format, ...) { \
static const char format_string[] = format; \
printf(format_string, ##__VA_ARGS__); \
timestamp(); \
}
int main()
{
printf_all("%d\n",10);
return 0;
}
I want to convert this macro into a function. But I am facing problems while passing in the arguments.
void printf_timestamp(static const char format_string[]) {
static const char format_string[] = format;
printf(format_string, ##__VA_ARGS__);
timestamp();
}
You can use vprintf:
int printf_timestamp(const char* fmt, ...) {
va_list args;
int result;
va_start(args, fmt);
result = vprintf(fmt, args);
va_end(args);
timestamp();
return result;
}
This is usually done using the vprintf() function, as orlp explained. However, that alone leaves you with a format that cannot be typechecked: Usually, your compiler interpretes the format string literal in every printf() call that it sees to determine whether the corresponding arguments have the right types.
Some compilers allow you to add support for this kind of type checking, here is the __attribute__(()) that is needed for gcc:
//within header
void printfTimestamp(const char* format, ...)
__attribute__((format(printf, 1, 2)));
//within implementation file
void printfTimestamp(const char* format, ...) {
va_list args;
va_start(args, format);
int result = vfprintf(stderr, format, args);
va_end(args);
timestamp();
return result;
}
The arguments to the attribute are the argument number with the format string (1) and the first variable argument position (2). As such, if you were to add an additional parameter to your function, you would declare it like this:
void myPimpedPrintf(int foo, const char* format, ...)
__attribute__((format(printf, 2, 3)));
For just adding a timestamp, I agree that vprintf() as proposed by orlp is the way to go. However, I think there is a valid argument in favor of macros, and that's the use of other compiler built-in macros like __LINE__, __FILE__, and __func__, which I personally find very useful for logging.
I generally use something like this with gcc and anything else that does comma swallowing.
#define log_debug(M, ...) do{ \
struct timespec _ts; \
double _ts_sec; \
clock_gettime(CLOCK_MONOTONIC, &_ts);\
_ts_sec = _ts.tv_nsec * 1e-9 + _ts.tv_sec; \
fprintf(stderr, "%.3f [DEBUG] (%s:%d) " M, _ts_sec, \
__func__, __LINE__, ##__VA_ARGS__); \
}while(0)
// usage:
log_debug("x=%d\n", x);
There are a couple "tricks" going on here you might not be familiar with.
The first of which is the do{}while() loop. This is a fairly common and largely portable C idiom for writing multi-statement macros. It lets you use the macro terminating it in a ; and allows declaration of scoped variables. However, is a statement, not an expression, so there's no "return value". Usually doesn't matter for printf() like macros, but be aware, this can bite you in other uses when trying to make function-like macros.
The other "trick" is the use of comma swallowing with the '##' operator. Read more here: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
Also, this takes advantage of the fact that back-to-back string literals are concatenated in C to form a single string literal. The downside is that this technique ONLY works with string literals, i.e. your format string cannot be in a variable.

Expanding a macro to a different default macro if an argument is missing

Is it possible to expand a macro which accepts multiple arguments to a different macro if first argument is not the expected value
E.g
int main()
{
PRINT(2, "%d%d\n", i, j); //should expand to syslog(2, "%d%d\n", i, j)
PRINT("%d%d\n", i, j); //arg1 which is expected to be an int is not preset.
/* This should expand differently may be to a default level say 3. syslog(3, "%d%d\n", i,j); */
}
I would have tried this kind of over loading if I knew total number of args.
I really recommend to write two separate macros for this, just as you would write two differently named functions for the two signatues in C. (I would rather write macros that tell you what level they are explicitly, like ERROR(...), WARNING(..) etc. than introduce a default argument.)
That said, there are two possibilities to achieve what you want.
C11 _Generic selections
The _Generic keyword was introduced with C11. It allows to expand macros in a switch-like manner according to the type of an argument; Robert Gamble has a good introduction.
You want to distinguish two cases: First argument is a string and first argument is an integer. A drawback is that in _Generic, a string literal isn't treated as char * or const char *, but as char[size]. For example, "%d" is a char[3].
In your case, we can get around this by treating a string as anything that isn't an integer. The compiler will sort out all non-string, non-integer arguments later. So:
#define PRINT(fmt, ...) \
_Generic(fmt, \
int: syslog(fmt, __VA_ARGS__), \
default: syslog(3, fmt, __VA_ARGS__))
There are drawbacks: You can't have a single-argument call, because that would leave a comma in the call. (gcc's ##__VA_ARGS__ gets around that.) And the _Generic keyword is not yet widely implemented; this solution will make your code highly unportable.
String introspection hack
Ordinary C99 macros have no information on their type. C code can make a guess, however. Here's an example that checks whether a macro argument is a string literal:
#define PRINT(sev, ...) \
if (#sev[0] == '"') syslog(3, sev, __VA_ARGS); \
else syslog(sev, __VA_ARGS__);
This works -- almost. The compiler will probably compile the constant condition away and only gererate code for one of the branches. But it will parse the branches anyway and the dead branch will have a wrong function signature, which will generate warnings.
You can get around this by writing a variadic front-end function in C. Here's an example that works:
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define HEAD(X, ...) X
#define STR_(x) #x
#define STR(x) STR_(x)
#define PRINT(...) \
msg(*STR(HEAD(__VA_ARGS__)) == '"', __VA_ARGS__)
int msg(int dflt, ...)
{
va_list va;
int sev = 3;
const char *fmt;
va_start(va, dflt);
if (!dflt) sev = va_arg(va, int);
fmt = va_arg(va, const char *);
fprintf(stderr, "[%d] ", sev);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
return 0;
}
int main()
{
PRINT(1, "Incompatible types %s and %s", "Apple", "Orange");
PRINT("Microphone test: %d, %d, %d, ...", 1, 2, 3);
return 0;
}
This solution is dangerous, because the msg function is only safe if it is generated by the macro. And the macro is only safe if the format string is a string literal beginning with a double quote. The macro expands the arguments by one boolean argument to the left and hides the argument incompatibility in a variadic argument list.
It may be a nice trick, but you'll be better off having separate, clearly named macros.
C macros do not have the ability to inspect their arguments. As noted in the answer you posted, there is a sneaky way to do different things based on the number of arguments, but that's the extent of it. If you already have a variable number of arguments outside of the overload you are trying to do, it will not be possible. If all you need is a default level:
#define PRINTNORM(...) PRINT(3, __VA_ARGS__)
or whatever you'd like to call it. IMHO, cleaner code than overloading PRINT.
Simply use another value for your need. And perhaps a bit of magic with variadic macro would help.
something like:
#define PRINT( print_level , print_string , ... )\
switch( print_level ) \
/* as many syslog cas as needed */
case( 5 ):\
case( 4 ):\
case( 3 ):\
case( 2 ):\
case( 2 ):\
case( 1 ):\
syslog( print_level , __VA_ARGS__ );\
break ; \
default: \
case( 0 ): \
printf( __VA_ARGS__ ); \ /* else we simply want to print it */
break ;
Edit:
Doc on variadic macro: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
P99 has conditional macro evaluation. Here you could probably use something like P99_IF_EMPTY for something like
#define PRINT(LEV, ...) my_print(P99_IF_EMPTY(LEV)(3)(LEV), __VA_ARGS__)
this would still have you insert a , for the case of the empty argument but comes probably close to what you want to achieve.
Optional arguments coming before other mandatory arguments can potentially be handled by folding them together in parentheses:
PRINT((2, "%d%d\n"), i, j);
PRINT("%d%d\n", i, j);
Define PRINT like this:
#define PRINT(SL, ...) PRINT_LEVEL(APPLY(CAT(LEVEL, IS_SPLIT(SL)), IDENTITY SL), APPLY(CAT(FSTRING, IS_SPLIT(SL)), IDENTITY SL), __VA_ARGS__)
#define PRINT_LEVEL(LEVEL, ...) syslog(LEVEL, __VA_ARGS__)
PRINT detects whether the first argument is an atom (just the format string) or a parenthesized list of two elements (printlevel + string), and expands into the real implementation PRINT_LEVEL accordingly, either extracting the level from the first argument, or supplying a default value.
Definitions for IS_SPLIT and the other helpers are as follows:
#define LEVEL_0(_S) 3
#define LEVEL_1(L, S) L
#define FSTRING_0(S) K_##S
#define FSTRING_1(L, S) S
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A ## B
#define APPLY(F, ...) F(__VA_ARGS__)
#define IDENTITY(...) __VA_ARGS__
#define K_IDENTITY
#define IS_SPLIT(...) IS_SPLIT_1(IDENTITY __VA_ARGS__)
#define IS_SPLIT_1(...) IS_SPLIT_2(__VA_ARGS__, _1, _0, _)
#define IS_SPLIT_2(_X, _Y, R, ...) R

Returning a Character String from #define Function

I know you can return a character string from a normal function in C as in this code
#include <stdio.h>
char* returnstring(char *pointer) {
pointer="dog";
return pointer;
}
int main(void)
{
char *dog = NULL;
printf("%s\n", returnstring(dog));
}
However, I can't find a way to be able to return character strings in #define functions, as in this code
#include <stdio.h>
#define returnstring(pointer) { \
pointer="dog"; \
return pointer; \
}
int main(void)
{
char *dog = NULL;
printf("%s\n", returnstring(dog));
}
I know that there are workarounds(like using the first program). I just want to know if it is possible
Thinking about a "#define function" is, IMO, the wrong way to approach this.
#define is a blunt instrument which amounts to a text find/replace. It knows little to nothing about C++ as a language, and the replace is done before any of your real code is even looked at.
What you have written isn't a function in its own right, it is a piece of text that looks like one, and it put in where you have written the alias.
If you want to #define what you just did, that's fine (I didn't check your example specifically, but in general, using #define for a function call and substituting the arguments is possible), but think twice before doing so unless you have an amazing reason. And then think again until you decide not to do it.
You can't "return" from a macro. Your best (ugh... arguably the "best", but anyway) bet is to formulate your macro in such a way that it evaluates to the expression you want to be the result. For example:
#define returnstring(ptr) ((ptr) = "hello world")
const char *p;
printf("%s\n", returnstring(p));
If you have multiple expression statements, you can separate them using the horrible comma operator:
#define even_more_dangerous(ptr) (foo(), bar(), (ptr) = "hello world")
If you are using GCC or a compatible compiler, you can also take advantage of a GNU extension called "statement expressions" so as to embed whole (non-expression) statements into your macro:
#define this_should_be_a_function(ptr) ({ \
if (foo) { \
bar(); \
} else { \
for (int i = 0; i < baz(); i++) { \
quirk(); \
} \
} \
ptr[0]; // last statement must be an expression statement \
})
But if you get to this point, you could really just write a proper function as well.
You don't return anything from a #defined macro. Roughly speaking, the C preprocessor replaces the macro call with the text of the macro body, with arguments textually substituted into their positions. If you want a macro to assign a pointer to "dog" and evaluate to the pointer, you can do this:
#define dogpointer(p) ((p)="dog")
The thing is returnstring as a macro does not do what it says; it also assigns the value to the parameter. The function does as it says, even if it (somewhat oddly) uses its parameter as a temporary variable.
The function is equivalent to:
char* returnstring(char *ignored) {
return "dog";
}
The function macro is much the same as:
#define returnstring(pointer) pointer = "dog"
Which begs the question, why not call it assign_string?
Or why not just have:
#define dogString "dog"
And write:
int main(void)
{
char *dog = NULL;
printf("%s\n", dog = dogString);
}
The function for assignString is:
char* assignstring(char **target{
*target= "dog";
return *target;
}
You can then have a macro:
assign_string_macro(pointer) assignstring(&pointer)
Ultimately if you want to "return character strings in #define functions", then all you need is:
#define returnstring(ignored) "dog"

Resources