Я пытаюсь создать макрос, который будет принимать предопределенный префикс и объединять его с именем требуемой функции в аргументе макроса, но мне это не удалось.
Например, пока это искомая сигнатура функции:
void somePrefix__someFunc(int a)
Однако, когда я запускаю его и проверяю таблицу символов программы, я получаю расширение:
FUNC_PREFIXsomeFunc
Что я делаю не так и как мне это сделать правильно?
Код, который я пытался запустить:
#include <iostream>
#define CONCAT(A, B) A##B
#define FUNC_PREFIX somePrefix__
#define FUNC_NAME(_func) CONCAT(FUNC_PREFIX, _func)
void FUNC_NAME(someFunc)(int a)
{
std::cout << a << std::endl;
}
int main()
{
FUNC_NAME(someFunc)(2);
return 0;
}
P.S: Я пробовал использовать макрос без обёртки CONCAT (напрямую пытаясь объединить FUNC_PREFIX##_func
), но это всё равно не сработало.
Ваш код у меня работает с MinGW x64 8.1.0. Мне не нужен другой уровень макроса. Какой компилятор вы используете?
##
всегда применяется перед (повторным) сканированием макроса «список замены», поэтому, если CONCAT
развернут перед другими элементами, мы не получим желаемого результата. Всякий раз, когда мы получаем ##
в списке замен во время замены макроса, он применяется перед любой дальнейшей заменой.
Поэтому вам нужен дополнительный вспомогательный макрос для расширения FUNC_PREFIX
, чтобы он был расширен до CONCAT
:
#include <stdio.h>
#define CONCAT(A, B) A##B
#define CONCAT_EXPAND(A, B) CONCAT(A,B)
#define FUNC_PREFIX somePrefix_
#define FUNC_NAME(func) CONCAT_EXPAND(FUNC_PREFIX, func)
void FUNC_NAME(someFunc)(int a)
{
printf("%s: %d\n",__func__, a);
}
int main()
{
FUNC_NAME(someFunc)(2);
return 0;
}
Выход:
somePrefix_someFunc: 2
Хотя именование функций с помощью макросов, подобных функциям, как правило, очень плохая идея...
Почему это такая плохая идея, если я могу спросить?
@TalAfek Потому что макросы, подобные функциям, делают код трудным для чтения, трудным в обслуживании и легко приводят к ошибкам. А также потому, что хорошие системы являются детерминированными, а имена идентификаторов используются главным образом для удобства программиста; поэтому представление о том, что имена идентификаторов могут постоянно меняться и тем самым сбивать с толку программиста, с самого начала часто ошибочно.
Хорошо, если это все, то в данном конкретном случае это действительно улучшает читаемость :) Большое спасибо!
Вам нужны два уровня макроса concat godbolt.org/z/TzTqPG6Ga (но имейте в виду, что использование двойного подчеркивания — это UB).