Написание макроса variadic, который использует имена переданных аргументов
Я хочу написать переменный макрос, который каким-то образом знает имена переданных аргументов. Например:
Код:
int x = 2;
float f = 4.6;
char c = 'A';
char* str = "Bla bla";
PRINT("%d %f %c %s", x, f, c, str); // calling the macro
должен произвести вывод
x=2 f=4.6 c=A str=Bla bla.
Надеюсь, кто-то знает ответ на этот вопрос.
6 ответов
Закрыть, но не совсем (работает только для одного выражения), что требовал запрашивающий:
#define PRINT(fmt, var) printf(#var " = " fmt, (var))
Вот пример:
#include <stdio.h>
#include <stdlib.h>
#define PRINT(fmt, var) printf(#var " = " fmt, (var))
int
main(int argc, char *argv[])
{
int x = 2, y = 3;
float f = 4.6;
char c = 'A';
char *str = "Bla bla";
PRINT("%d\n", x);
PRINT("%f\n", f);
PRINT("%c\n", c);
PRINT("%s\n", str);
PRINT("%d\n", x+y);
exit(EXIT_SUCCESS);
}
Я не думаю, что вы можете достичь того, что вы хотите.
Но что-то вроде этого может быть вашим:
#define PRINT(fmt, val) fprintf(stderr, "%s=" fmt, #val, val)
...
int x = 2;
float f = 4.6;
char c = 'A';
char* str = "Bla bla";
// calling the macro:
PRINT("%d ", x);
PRINT("%f ", f);
PRINT("%c ", c);
PRINT("%s\n", str);
Слегка то, что вы можете хотеть:
#include <stdio.h>
#define STRINGIFY(x) #x, (x)
#define FPRINTF(file, fmt, ...) fprintf(file, fmt, __VA_ARGS__)
#define PRINTF(fmt, ...) FPRINTF(stdout, fmt, __VA_ARGS__)
int main(void)
{
int i = 42;
char ch = 'a';
char str[4] = "alk";
PRINTF("%s=%s, %s=%c, %s=%d\n",
STRINGIFY(str),
STRINGIFY(ch),
STRINGIFY(i)
);
/* of just use printf directly: */
printf("%s=%s, %s=%c, %s=%d\n",
STRINGIFY(str),
STRINGIFY(ch),
STRINGIFY(i)
);
return 0;
}
Внимательно прочитайте документацию cpp. В частности, о макроаргументах, строковых, конкатенационных и вариационных макросах. Там все хорошо объяснено.
Возможно, вы не сможете достичь именно того, чего хотите, потому что вам нужно разделить строку формата.
Возможно, снизить ваши цели (например, принять только один аргумент в пользу PRINT
посмотрите те или иные ответы) или подумайте об использовании более мощного препроцессора, такого как GPP.
Вы также можете настроить GCC (добавив свои встроенные функции), например, с помощью MELT, но это, вероятно, не стоит тех недель (для новичка), которые требуются для этого.
/ Надевает шляпу Индианы Джонса /
Возможно, я немного опоздал, но я здесь, чтобы сказать, что у этой проблемы есть правильное (-ое) решение.
Во-первых, некоторые предварительные условия определяют ( объяснение здесь):
#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], но ее легко расширить на любое количество аргументов, особенно на степени 2. Однако, чем больше аргументов она поддерживает, тем менее элегантно она выглядит.
PS: @BasileStarynkevitch уже предоставил все нужные ссылки, чтобы уточнить, как это работает.
Следующее работает для меня в GCC 4.7:
#include <stdio.h>
#define PRINT(...) fprintf (stderr, __VA_ARGS__)
int main()
{
int x = 2;
float f = 4.6;
char c = 'A';
char* str = "Bla bla";
PRINT("%d %f %c %s", x, f, c, str); // calling the macro
}
(обратите внимание, что я отредактировал вызов макроса, изменив%s для%c)
С уважением