Условное расширение макроса - PullRequest
7 голосов
/ 13 июня 2010

Heads up: это странный вопрос.

У меня есть несколько действительно полезных макросов, которые я хотел бы использовать для упрощения ведения журнала. Например, я могу сделать Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3"), и это будет расширено до более сложного вызова метода, который включает в себя такие вещи, как self, _cmd, __FILE__, __LINE__ и т. Д., Чтобы я мог легко отслеживать, где что-то регистрируются. Это прекрасно работает.

Теперь я хотел бы расширить свои макросы, чтобы они работали не только с методами Objective-C, но и с общими функциями C. Проблема заключается в частях self и _cmd, которые находятся в расширении макроса. Эти два параметра не существуют в функциях C. В идеале я хотел бы иметь возможность использовать этот же набор макросов в функциях C, но у меня возникают проблемы. Когда я использую (например) мой макрос 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.

появляется сообщение об ошибке: «#» не сопровождается параметром макроса ».

Другой моей мыслью было создание второго набора макросов, специально для использования в функциях Си. Это пахнет плохим запахом кода, и я действительно не хочу этого делать.

Можно ли как-то использовать один и тот же набор макросов как в методах Objective-C, так и в функциях C, и ссылаться только на self и _cmd, если макрос используется в методе Objective-C?

edit больше информации:

thisFunctionIsACFunction определяется довольно элементарно (и я определенно открыт для улучшений и предложений). В основном это так:

BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+');

Он полагается на поведение компилятора, добавляющего «-» или «+» для методов экземпляра и класса к объектам Objective-C. Все остальное должно быть функцией C (поскольку функции C не могут иметь имен, начинающихся с '-' или '+').

Я понимаю, что эта проверка технически является проверкой во время выполнения, поскольку __PRETTY_FUNCTION__ заменяется на char*, и это, вероятно, является основным препятствием для моего запроса о помощи.

Ответы [ 3 ]

7 голосов
/ 13 июня 2010

Препроцессор выполняет всю свою работу до фактического анализа кода. Препроцессор не может узнать, является ли функция 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, будем надеяться, будут скрывать их со своими собственными определениями.

1 голос
/ 04 сентября 2012

Вы можете использовать

if defined "abc" <statement1>
else if defined "def" <statement2>
0 голосов
/ 13 июня 2010

Вы можете использовать какой-то условный макрос:

#ifndef OBJECTIVE_C
  #define self 0
  #define _cmd ""
#endif

Я не совсем уверен, что вы должны определить self и _cmd, это были только догадки.

Я не уверен, есть ли предопределенный макрос, который вы можете проверить, компилируете ли вы в Objective C, поэтому вам может потребоваться определить OBJECTIVE_C вручную как часть вашей сборки.

...