Условное расширение макроса
Heads up: это странный вопрос.
у меня есть очень полезные макросы, которые мне нравится использовать для упрощения некоторых журналов. Например я могу сделать Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3")
, и это будет расширено в более сложный вызов метода, который включает в себя такие вещи, как self
, _cmd
, __FILE__
, __LINE__
и т. д., чтобы я мог легко отслеживать, где все регистрируется. Это отлично работает.
теперь я хотел бы расширить свои макросы, чтобы не только работать с методами Objective-C, но и общие функции C. Проблема в self
и _cmd
части, которые находятся в расширении макроса. Эти два параметра не существуют в функциях C. В идеале я хотел бы иметь возможность использовать этот же набор макросов в функциях C, но у меня возникают проблемы. Когда я использую (например) my Log()
макрос, я получаю предупреждения компилятора о self
и _cmd
быть необъявленным (что имеет полный смысл).
моей первой мыслью было сделать что-то вроде следующего (в моем макрос):
if (thisFunctionIsACFunction) {
DoLogging(nil, nil, format, ##__VA_ARGS__);
} else {
DoLogging(self, _cmd, format, ##__VA_ARGS__);
}
это все еще создает предупреждения компилятора, так как весь оператор if () заменяется вместо макроса, что приводит к ошибкам с self
и _cmd
ключевые слова (даже если они никогда не будут выполняться во время выполнения функции).
моей следующей мыслью было сделать что-то вроде этого (в моем макро):
if (thisFunctionIsACFunction) {
#define SELF nil
#define CMD nil
} else {
#define SELF self
#define CMD _cmd
}
DoLogging(SELF, CMD, format, ##__VA_ARGS__);
к сожалению, это не работает. Я получаю "ошибка:" # "не сопровождается параметром макроса" на моем первом #define
.
другой моей мыслью было создать второй набор макросов, специально для использования в функциях C. Это пахнет плохим кодом, и я действительно не хочу этого делать.
есть ли способ использовать один и тот же набор макросов как из методов Objective-C, так и из функций C, и только reference self
и _cmd
если макрос находится в методе Objective-C?
редактировать больше информация:
thisFunctionIsACFunction
определяется довольно рудиментарным способом (и я определенно открыт для улучшений и предложений). В основном это так:
BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+');
он полагается на поведение компилятора, чтобы добавить " - "или"+", например, и методы класса для объектов Objective-C. Все остальное должно быть функцией C (поскольку функции C не могут иметь имена, начинающиеся с " - "или"+").
я понимаю, что эта проверка является технически проверка выполнения , с __PRETTY_FUNCTION__
заменяется на тег char*
, и это, вероятно, главный блокпост для моей просьбы о помощи.
3 ответов
препроцессор выполняет всю свою работу до фактического анализа кода. Препроцессор не может знайте, является ли функция C или obj-C, потому что она запускается до анализа кода.
по той же причине,
if (thisFunctionIsACFunction) {
#define SELF nil
#define CMD nil
} else {
#define SELF self
#define CMD _cmd
}
DoLogging(SELF, CMD, format, ##__VA_ARGS__);
не может работать - #defines обрабатываются до этапа компиляции.
таким образом, сам код должен содержать проверку "время выполнения" (хотя компилятор может оптимизировать это).
Я бы предложил определение что-то вроде
void *self = nil; //not sure about the types that
SEL _cmd = nil; //would be valid for obj-c
в глобальной области; функции C будут "видеть" эти определения, в то время как методы Objective-C, надеюсь, скроют их своими собственными определениями.
вы можете использовать какой-то макрос условное:
#ifndef OBJECTIVE_C
#define self 0
#define _cmd ""
#endif
Я не совсем уверен, что вы должны определить self
и _cmd
чтобы это были просто догадки.
Я не уверен, есть ли предопределенный макрос, который вы можете проверить, компилируете ли вы в Objective C, поэтому вам может потребоваться определить OBJECTIVE_C
вручную как часть сборки.