Писане на променлив макрос, който използва имената на предадените аргументи

Искам да напиша променлив макрос, който по някакъв начин знае имената на предадените аргументи. Например:

Кодът:

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.

Дано някой знае отговора на това.


person user3115040    schedule 07.01.2014    source източник
comment
за char print е %c, а не %s Актуализирах въпроса с това   -  person MOHAMED    schedule 07.01.2014
comment
Почти съм сигурен, че не може да стане.   -  person JeremyP    schedule 07.01.2014
comment
Към OP: Сигурни ли сте, че искате точно това? Не може да се направи лесно! (Но ако прекарате няколко дни или седмици в работа, може да получите нещо близко).   -  person Basile Starynkevitch    schedule 07.01.2014
comment
Кой проблем се опитвате да разрешите?   -  person Mr Lister    schedule 07.01.2014
comment
Невъзможно е по точния начин на вашия пример: низов литерал като "%d %f %c %s" не може да бъде разделен, разширен по средата или модифициран от C препроцесора. Може да работи само за единични параметри, тъй като конкатенацията на низ позволява добавяне на друг низ към литерал на низ.   -  person Jens    schedule 07.01.2014
comment
@Jens: Наистина. Разбира се, автоматичното сглобяване на форматиращ низ (например чрез предаване на формат заедно с аргументите или извеждането им чрез генерични типове C11) вероятно ще бъде по-лесно за използване така или иначе   -  person doynax    schedule 07.01.2014


Отговори (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);
}
person Lee Duhem    schedule 07.01.2014
comment
@Dipto Да, прав си и затова казах „близо, но не точно“ :-) - person Lee Duhem; 07.01.2014
comment
Печатна грешка: не сигнал, а единична променлива! - person Basile Starynkevitch; 07.01.2014
comment
@leeduhem Чувствайте се свободни да върнете назад. Изглежда, че моята редакция е изтрила вашата. - person ; 07.01.2014
comment
@remyabel 'single' е добре. Но мисля, че „единичен израз“ е по-точен, този макрос също работи за x+y. - person Lee Duhem; 07.01.2014

Не мисля, че можеш да постигнеш това, което искаш.

Но нещо подобно може да е ваше:

#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);
person glglgl    schedule 07.01.2014

Прочетете внимателно документацията на cpp. По-специално относно макро аргументи, стрингификация, конкатенация и вариални макроси. Там е добре обяснено.

Вероятно може да не успеете да постигнете точно това, което искате, защото трябва да разделите форматиращия низ.

Може да намалите целите си (напр. приемете само един аргумент за PRINT, вижте това или това отговаря) или обмислете използването на по-мощен препроцесор като GPP.

Можете също така да персонализирате GCC (като добавите вашите вградени) с напр. MELT, но това вероятно не си струва седмиците усилия (за начинаещ), необходими за това.

person Basile Starynkevitch    schedule 07.01.2014

Малко това, което може да искате:

#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;
}
person alk    schedule 07.01.2014

/Слага шапка на Индиана Джоунс/

Може да съм малко закъснял, но съм тук, за да кажа, че този проблем има подходящо (не) решение.

Първо, някои предпоставки дефинират (обяснение тук ):

#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. Въпреки това, колкото повече аргументи поддържа, толкова по-малко елегантно изглежда.

P.S.: @BasileStarynkevitch вече предостави всички правилни връзки, за да изясни как работи това.

person hidefromkgb    schedule 18.10.2016

Следващото работи за мен в 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)

за разбирането

person Jesús Casado    schedule 07.01.2014
comment
Той също така не показва името x (само неговата стойност), което е това, което OP иска. - person Basile Starynkevitch; 07.01.2014