Как переименовать макрос препроцессора C?

Рассмотрим заголовок lib.h для чтения (только для чтения)

#define XYZ 42

В исходном файле я хочу использовать слово XYZ для несвязанной цели и не хочу, чтобы подстановка была с 42. Но в том же исходном файле для других целей я также хочу получить доступ к значению 42 из lib.h без его жесткого кодирования. Как переименовать макрос из XYZ, скажем, LIB_XYZ?

Следующее не работает, поскольку препроцессор хочет XYZ во время подстановки LIB_XYZ, но XYZ был undefined:

#include "lib.h"
#define LIB_XYZ XYZ
#undef XYZ

Есть ли способ обмануть препроцессор в расширение LIB_XYZ до его окончательного значения до того, как XYZ будет потерян?

Ответы

Ответ 1

Не с предварительным процессором, по крайней мере, не с тем, что я знаю.

Однако для простых констант с известным типом, как в вашем примере, существует обходное решение.

#include <stdio.h>

// <xyz.h>

#define XYZ 42

// </xyz.h>

enum xyz_constants
{
  LIB_XYZ = XYZ,
};

#undef XYZ

#define XYZ 27

int
main()
{
  printf("old value: %d, new value: %d\n", LIB_XYZ, XYZ);
  return 0;
}

Не показывая пух от stdio.h, этот код предварительно обрабатывается следующим образом.

enum xyz_constants
{
  LIB_XYZ = 42,
};

int
main()
{
  printf("old value: %d, new value: %d\n", LIB_XYZ, 27);
  return 0;
}

Вы можете в некоторой степени распространить это на другие типы данных и некоторые макросы, подобные функциям, но, конечно, существуют ограничения.

В любом случае, зачем вам нужен конкретный идентификатор XYZ? Не можете ли вы использовать другое имя для своего макроса?

Ответ 2

Если XYZ из lib.h является числом [или константой разнообразия], вы можете использовать enum:

enum { LIB_XYZ = XYZ };
#undef XYZ

Если XYZ не указано выше, вам необходимо создать (например) myxyz.c, который не включает lib.h и использовать XYZ там (другие файлы могут включать xyz.h)

Отличие состоит в том, что #define LIB_XYZ XYZ не будет разрешено в этой строке, только когда вы используете его позже, как в:

foo(LIB_XYZ);

так что это не сработает, потому что вы уже #undef'ed XYZ.

Ответ 3

Символ препроцессора - это имя. Не существует директивы предварительной обработки, которая изменяет само имя, сохраняя его содержимое. Например, учитывая либо:

#define FOO 42

или же

#define FOO(x, y)  x ## y (

Нет способа определить макрос с именем BAR который имеет такое же содержимое, без повторения этих определений. То есть, нет такой операции, как:

#alias BAR FOO  // nonexistent fantasy macro-cloning preprocessor directive

Ни как это:

#rename BAR FOO // like #alias BAR FOO followed by #undef FOO

Если мы сделаем это:

#define BAR FOO  // for the #define FOO 42 case

это не псевдоним. Макрос BAR определяется так, что его последовательностью замены токена является токен FOO, а не 42. Если макрос FOO исчезает, то BAR теряет свое значение.

Также обратите внимание, что макросы препроцессора C не могут расширяться до директив препроцессора, поэтому следующий подход также не будет работать:

 // wrong:
 #define MACRO_DEFINER(NAME) \
   #define NAME 42

 MACRO_DEFINER(FOO) // hoping for #define FOO 42: no such luck
 MACRO_DEFINER(BAR) // hoping for #define BAR 42: likewise

Я боюсь, что вам нужно сделать несколько шагов назад, чтобы найти альтернативную стратегию для любой проблемы, которую вы пытаетесь решить. Если вы застряли, создайте новый вопрос о актуальной проблеме.

Всегда есть генерация кода: генерация C или C++ во время сборки. Тогда любая текстовая замена или расширение, о котором вы можете мечтать, возможны, если вы просто настроите свою систему генерации.

Любое решение с использованием #undef XYZ рискует нарушить функциональность заголовка библиотеки. Библиотека может сделать что-то вроде этого:

#define XYZ 42 # определить макро (B) bloop (XYZ, B)

Если мы используем macro, то мы нарушаем его, если переопределяем XYZ.

Если библиотека известна тем, что она определяет XYZ и нам удастся успешно переопределить ее в коде, который использует эту библиотеку, ситуация будет сбивать с толку будущих сопровождающих. "О, этот XYZ самом деле не тот библиотечный; этот программист просто хотел иметь не связанный XYZ ".

Лучшее решение здесь - перестать хотеть использовать XYZ и найти другое имя. Адаптироваться к библиотекам, которые вы используете; не конфликтуй с ними.

Ответ 4

Используйте другой .c файл и назначьте значение макроса глобальной переменной.