/Надевает шляпу Индианы Джонса/
Я могу быть слишком поздно, но я здесь, чтобы сказать, что у этой проблемы действительно есть правильное решение.
Во-первых, некоторые предварительные условия определяют (объяснение здесь ):
#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)
Затем код, который на самом деле является расширением ответа @alk:
#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;
}
Эта версия подходит только для [0..16] аргументов, но ее можно легко распространить на любое количество аргументов, особенно на степень двойки. Однако чем больше аргументов она поддерживает, тем менее элегантно она выглядит.
P.S.: @BasileStarynkevitch уже предоставил все нужные ссылки, чтобы прояснить, как это работает.
person
hidefromkgb
schedule
18.10.2016
"%d %f %c %s"
, не может быть выделен, дополнен в середине или изменен препроцессором C. Он может работать только для одиночных параметров, потому что конкатенация строк позволяет добавить другую строку перед строковым литералом. - person Jens   schedule 07.01.2014