Использование макросов C для создания кода в стиле C, который сопоставляется с вызовами сообщений Objective-C? - PullRequest
6 голосов
/ 29 октября 2011

Я уверен, что я получу 20 человек, которые скажут: «Зачем тебе это делать?», Но я собираюсь задать свой вопрос, тем не менее, потому что он носит академический характер.

Я хотел бы использовать макросы C для переопределения [ClassName new] в нечто вроде: new(ClassName), и мне интересно, как это сделать.Я не очень удобен с макросами C для начала (я знаю - неловко - я должен быть) - и мне определенно не удобно смешивать их с моим кодом Objective-C.Итак, по вопросу ...

Во-первых, если это препроцессор, могу ли я сделать простую замену, например, такую:

#define new(x) [x new]

или, по какой-либо причине, мне нужноперейти к среде выполнения target-c и сделать что-то более похожее на:

#define new(x) objc_msgSend(class_createInstance(x, 0), sel_registerName("init"))

Каковы недостатки выполнения чего-то подобного?

Часто ли такие вещи используютсядругие, или кто-то посмотрит на это и скажет "какого чёрта ты там делаешь"?(и я должен заботиться)

Спасибо

РЕДАКТИРОВАТЬ:

Мне пришло в голову после публикации этого, что я, на самом деле, вижу этотакие вещи раньше - в библиотеке Three20, где они делают такие вещи:

#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
#define TT_INVALIDATE_TIMER(__TIMER) { [__TIMER invalidate]; __TIMER = nil; }

// Release a CoreFoundation object safely.
#define TT_RELEASE_CF_SAFELY(__REF) { if (nil != (__REF)) { CFRelease(__REF); __REF = nil; } }

Так что, вероятно, мой вопрос становится простым;Каковы недостатки этого, и является ли это относительно принятой практикой или чем-то, что может принести мне больше неприятностей, чем оно того стоит?

Ответы [ 3 ]

3 голосов
/ 29 октября 2011

Макросы обрабатываются первыми и работают с исходным кодом в виде простого текста.Так что да, вы можете сделать так, чтобы ваш макрос new генерировал синтаксис Objective-C или простой синтаксис C, или даже недопустимый синтаксис, если хотите.

Недостатки использования макроса в целом таковы, потому что он анализируется иобработанный на отдельном шаге, можно написать макросы, которые не ведут себя так, как вы ожидаете, даже когда все выглядит хорошо.

Например, этот макрос:

#define MAX(x,y) x > y ? x : y

выглядит хорошо, носкажем, вы использовали это так:

z = MAX(a,MAX(b,c));

Это будет расширено препроцессором во что-то вроде этого:

z = a > b > c ? b : c ? a : b > c ? b : c;

Что на самом деле не даст вам максимум трех аргументов,Чтобы решить эту проблему, вам нужно обильно посыпать круглые скобки в определении макроса, даже если вы не думаете, что это необходимо:

#define MAX(x,y) ((x) > (y) ? (x) : (y));

Это исправляет это, за исключением того, что я добавил точку с запятой в конец, что являетсяПонятная привычка писать много кода на C, за исключением того, что теперь наш макрос расширяется до:

z = ((a) > (((b) > (c) ? (b) : (c));) ? (a) : (((b) > (c) ? (b) : (c));));;

Синтаксические ошибки!

Если вы посмотрите, как на самом деле определено MAX в Objective-CЭто довольно беспорядок, но это то, что вы должны сделать, чтобы безопасно писать макросы.И вам также нужно учитывать, что:

z = MAX(expensiveComputation(), reallyExpensiveComputation())

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

Итак, чтобы ответить на ваш вопрос, да, это вполне возможно, но написать безопасные макросы действительно сложно.И вы делаете это, чтобы вы могли притвориться, что ваш код Objective C фактически является кодом на другом языке ... В любом случае, зачем вам это нужно?

3 голосов
/ 29 октября 2011
* Макросы

C гарантированно

  • не являются рекурсивными
  • не расширяют функциональные макросы, за которыми не следует ()

, поэтому вашПервый вариант будет в порядке для препроцессора C.Единственные идентификаторы, которые зарезервированы (чтобы вы не могли использовать их для имен макросов), это ключевые слова и идентификаторы, начинающиеся с подчеркивания.new не является ни ключевым словом (для C), ни начинающимся с подчеркивания, так что это хорошо для препроцессора C.

Я не знаю, накладывает ли target-C другие ограничения, вам придетсяИщите это.

И да, я определенно тот парень, который спрашивает «зачем вам это делать?» .Не делайте этого, даже не думайте об этом, если, с другой стороны, вы чувствуете необходимость задать свой вопрос.

1 голос
/ 29 октября 2011

Предполагая, что вы используете последнюю версию GCC (версия 4.6), вы можете подумать о создании плагина GCC или, предпочтительно, GCC MELT расширение , для такой задачи.MELT - это высокоуровневый домен-специфичный язык для простого расширения GCC.

Например, ваш макрос new будет иметь значение

#define new(X) _mybuiltin_new_(X)

, а затем ваше расширение MELT добавит новую встроенную GCC_mybuiltin_new_, который будет преобразован в более простую Gimple (внутреннее представление, используемое GCC).Однако на разработку такого рода вещей уходит некоторое время (по крайней мере, неделя, а не часы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...