/Puts on Indiana Jones` hat/
I may be a tad too late, but I`m here to say that this problem does have a proper(-ish) solution.
First, some prerequisite defines (explanation here):
#define L(c, ...) \
L4(c,1,0,,,,,,,,,,,,,##__VA_ARGS__) L4(c,0,1,,,,,,,,,##__VA_ARGS__) \
L4(c,0,2,,,,, ##__VA_ARGS__) L4(c,0,3, ##__VA_ARGS__)
#define L4(c, f, n, ...) \
L3(c,f,n##0,,,,__VA_ARGS__) L3(c,0,n##1,,,__VA_ARGS__) \
L3(c,0,n##2,, __VA_ARGS__) L3(c,0,n##3, __VA_ARGS__)
#define L3(...) L2(__VA_ARGS__, \
1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, )
#define L2(c, f, \
n00,n01,n02,n03, n04,n05,n06,n07, n08,n09,n0A,n0B, n0C,n0D,n0E,n0F, \
a00,a01,a02,a03, a04,a05,a06,a07, a08,a09,a0A,a0B, a0C,a0D,a0E,a0F, \
s, ...) L##s(c, f, n00, a00)
#define L1(c, f, n, a) c##f(n, a)
#define L0(c, f, n, a)
Then the code, which is actually an extension of @alk`s answer:
#include <stdio.h>
#define STRING1(n, a) #a, (a)
#define STRING0(n, a) , STRING1(n, a)
#define PRINTF(fmt, ...) printf(fmt, L(STRING, __VA_ARGS__))
int main(int argc, char *argv[]) {
int i = 42;
char ch = 'a';
char str[4] = "alk";
/** every var must be preceded with '%s' for its name to be shown **/
PRINTF("%s=%s, %s=%c, %s=%d\n", str, ch, i);
return 0;
}
This version is only suited for [0..16] arguments, but it can be easily extended to any argument count, especially to powers of 2. However, the more arguments it supports, the less elegant it looks.
P.S.: @BasileStarynkevitch has already provided all the right links to clarify how this works.
"%d %f %c %s"
can't be picked apart, augmented in the middle or modified by the C preprocessor. It can only work for single parameters because string concatenation allows to prepend another string to a string literal. – Jens