Расширение и строковое форматирование макроса: как получить имя макроса (а не его значение) в виде строки, используя другой макрос?

Из интереса:

#define _ACD 5, 5, 5, 30

#define DEFAULT_NETWORK_TOKEN_KEY_CLASS   _ACD 

#define DEFAULT_NETWORK_TOKEN_KEY { DEFAULT_NETWORK_TOKEN_KEY_CLASS }

Используя только макрос DEFAULT_NETWORK_TOKEN_KEY_CLASS, как получить _ACD в виде строки в const без знака char [].

const uint8 startMsg[] = ?? DEFAULT_NETWORK_TOKEN_KEY_CLASS ;

Будет только _ACD.

Что будет правильным расширением макроса для получения _ACD здесь. В контексте Как структурировать макрос, имеющий массив как #define a_macro {5,7,7,97}?

1 ответ

Решение

(Здесь применяется стандартная оговорка об отказе от злоупотребления препроцессором C без уважительной причины.)

Конечно, можно делать то, что ты хочешь делать. Тебе необходимо STRINGIFY макрос и немного косвенности макроса.

Как правило, STRINGIFY определяется с одним уровнем косвенности, чтобы позволить препроцессору C расширять свои аргументы до того, как они претерпят строковое преобразование. Одна реализация:

/* The # operator converts symbol 'v' into a string */
#define STRINGIFY0(v) #v
#define STRINGIFY(v) STRINGIFY0(v)

Однако вы обнаружите, что этого недостаточно:

#define _ACD 5, 5, 5, 30
#define DEFAULT_NETWORK_TOKEN_KEY_CLASS   _ACD 
#define DEFAULT_NETWORK_TOKEN_KEY { DEFAULT_NETWORK_TOKEN_KEY_CLASS }

#define START_MSG STRINGIFY(DEFAULT_NETWORK_TOKEN_KEY_CLASS)
const char startMsg[] = START_MSG;

Вот, STRINGIFY(DEFAULT_NETWORK_TOKEN_KEY_CLASS) расширяется до STRINGIFY0(5,5,5,30)и препроцессор С жалуется, что вы дали STRINGIFY0 слишком много доводов.

Решение состоит в том, чтобы задержать расширение _ACD так что расширяется только до 5,5,5,30 когда захочешь. Для этого определите его как функциональный макрос:

#define _ACD() 5, 5, 5, 30

Сюда, _ACD будет расширен, только когда вы "позвоните": _ACD(), DEFAULT_NETWORK_TOKEN_KEY_CLASS теперь расширится до _ACDи вы должны расширить его, "позвонив": DEFAULT_NETWORK_TOKEN_KEY_CLASS(),

Следующий код иллюстрирует решение:

#include <stdio.h>

#define STRINGIFY0(v) #v
#define STRINGIFY(v) STRINGIFY0(v)

#define _ACD() 5, 5, 5, 30
#define DEFAULT_NETWORK_TOKEN_KEY_CLASS   _ACD 
#define DEFAULT_NETWORK_TOKEN_KEY { DEFAULT_NETWORK_TOKEN_KEY_CLASS() }

#define START_MSG STRINGIFY(DEFAULT_NETWORK_TOKEN_KEY_CLASS)

const char startMsg[] = START_MSG;

int main(int argc, char** argv)
{
  printf("%s\n",startMsg);
  return 0;
}
Другие вопросы по тегам