Динамически префикс имени макроса с помощью макроса variadic
Фон
Я использовал набор макросов препроцессора из другого вопроса, который позволяет мне ставить префиксы имен символов (перечисления, имена функций, имена структур и т. Д.) В моем источнике, то есть:
#include <stdio.h>
#define VARIABLE 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun, VARIABLE)
void NAME(func)(int i);
int main(void)
{
NAME(func)(123);
return 0;
}
void NAME(func)(int i)
{
printf("i is %d in %s.\n", i, __func__);
}
проблема
Это работает, как и ожидалось, со следующим выводом: i is 123 in func_3.
редактировать
Я хотел бы этот код:
#define NAME(SOME_MACRO_CONST) (123)
#define NAME(SOME_MACRO_CONST2) (123)
Расширить до:
#define 3SOME_MACRO_CONST (123)
#define 3SOME_MACRO_CONST2 (123)
Я понимаю, что макрос не должен начинаться с цифры. В конечном коде я буду использовать такие имена, как LIB_A_
а также LIB_B_
в качестве префиксов.
/Редактировать
Однако, если я попытаюсь сделать то же самое с макросами в качестве аргументов моего NAME
макрос variadic не работает так:
Повторное использование NAME
макрос:
Код
#define NAME(MY_CONST) (3)
Выход
test.c:7:0: warning: "NAME" redefined
#define NAME(MY_CONST) 3
Вставка префикса вручную:
Код:
#define VARIABLE ## MY_CONST (3)
Выход:
test.c:8:18: error: '##' cannot appear at either end of a macro expansion
#define VARIABLE ## MY_CONST (3)
Вопрос
Как я могу создать простые определения макросов (имя + значение), которые имеют общий префикс для всех макросов? Цель состоит в том, чтобы иметь возможность сделать несколько копий исходного файла и скомпилировать их с разными флагами, чтобы все версии можно было связать вместе в один и тот же конечный двоичный файл без коллизий имен символов / макросов (макросы позже будут перемещены в заголовочные файлы). Конечный файл будет слишком большим, чтобы писать что-то вроде M4 или языка шаблонов. В идеале решение должно включать возможность использования одной макрофункции /variadic-макроса для всех случаев использования, но я в порядке с одним макросом для префикса символа, а другим - для префикса имени макроса.
1 ответ
Я хотел бы этот код:
#define NAME(SOME_MACRO_CONST) (123) #define NAME(SOME_MACRO_CONST2) (124)
Расширить до:
#define 3SOME_MACRO_CONST (123) #define 3SOME_MACRO_CONST2 (124)
(Я исправил второе число до 124, чтобы оно отличалось от первого для удобства чтения)
Это невозможно с препроцессором C
по нескольким причинам:
3SOME_MACRO_CONST
не является допустимым идентификатором (как для препроцессора, так и для самого компилятора C), поскольку он не начинается с буквы или подчеркивания. Итак, давайте предположим, что вы хотите, чтобы ваш код был расширен до:/// new desired expansion #define THREE_SOME_MACRO_CONST (123) #define THREE_SOME_MACRO_CONST2 (124)
это все еще невозможно, потому что препроцессор работает раньше всего и не может генерировать никаких директив препроцессора (например,
#define
).
Обходной путь, если вы хотите только #define
некоторые числа (вычисляемые во время компиляции!!!) могут быть расширены до некоторого анонимного enum
лайк
enum {
THREE_SOME_MACRO_CONST= 123,
THREE_SOME_MACRO_CONST2= 124,
};
и вы знаете, как сделать это в деталях. Читайте также о X-макросах.
Тем не менее, даже если вы можете изменить свое требование на что-то, что возможно, это может быть не рекомендуется, потому что ваш код становится очень нечитаемым (IMHO). Иногда вы можете написать какой-нибудь простой скрипт (например, в sed
или же awk
...), или используйте какой-нибудь другой препроцессор, такой как GPP, для создания файла C из чего-то другого.
Обратите внимание, что наиболее серьезные инструменты автоматизации сборки (такие как GNU make или ninja) - или даже IDE (их можно настроить) позволяют довольно легко (путем добавления дополнительных целей, рецептов, команд и т. Д.) Генерировать C (или C++) из какого-то другого файла, и эта практика метапрограммирования регулярно используется на протяжении десятилетий (например, bison, flex, autoconf, rpcgen, Qt). moc
, SWIG...) так что я удивлен, что вы не можете сделать это. Создание файла заголовка, содержащего много #define
Это настолько распространенная практика, что я удивлен, что вам запрещено это делать. Возможно, вам просто нужно обсудить с вашим менеджером или коллегами. Может быть, вам нужно искать более интересную работу.
Лично мне очень нравятся такие подходы метапрограммирования (я защитил докторскую диссертацию по ним в 1990 году и обсуждал их на каждом собеседовании; работа, в которой метапрограммирование запрещено, не для меня. Посмотрите, например, на мой прошлый GCC Проект MELT, и мой будущий проект также будет иметь метапрограммирование). Еще один способ продвижения этого подхода - защитить языки, специфичные для предметной области (и возможность сделать свой DSL внутри какого-то большого программного проекта; например, компилятор GCC содержит около дюжины таких DSL…). Затем ваш DSL может (естественно) быть скомпилирован в C, что является обычной практикой. В современных операционных системах, которые генерировали C-код, можно скомпилировать во время выполнения и динамически загрузить как (сгенерированный) плагин (используя dlopen в POSIX...)
Иногда вы можете обмануть компилятор. Для проекта, скомпилированного GCC, вы можете подумать о написании своего плагина GCC..... (это намного больше, чем добавление команды, генерирующей код на C; ваш плагин может предоставить дополнительные магические прагмы или встроенные функции или атрибуты, используемые некоторыми другими макросами).
Вы также можете настроить файл спецификации вашего gcc
специально обрабатывать некоторые C-файлы. Осторожно, это может повлиять на любой будущий сборник!