Как переименовать макрос препроцессора 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 файл и назначьте значение макроса глобальной переменной.