Учебники

Препроцессоры Objective-C

Препроцессор Objective-C не является частью компилятора, но является отдельным этапом в процессе компиляции. Проще говоря, препроцессор Objective-C — это всего лишь инструмент подстановки текста, который инструктирует компилятор выполнить необходимую предварительную обработку перед фактической компиляцией. Мы будем называть препроцессор Objective-C OCPP.

Все команды препроцессора начинаются с символа решетки (#). Это должен быть первый непустой символ, и для удобства чтения директива препроцессора должна начинаться с первого столбца. В следующем разделе перечислены все важные директивы препроцессора —

Sr.No. Директива и описание
1

#define

Заменяет макрос препроцессора

2

#включают

Вставляет определенный заголовок из другого файла

3

#undef

Определяет макрос препроцессора

4

#ifdef

Возвращает true, если этот макрос определен

5

#ifndef

Возвращает true, если этот макрос не определен

6

#если

Проверяет, верно ли условие времени компиляции

7

#else

Альтернатива для #if

8

#elif

# еще #if в одном утверждении

9

#endif

Завершает препроцессор условно

10

#ошибка

Распечатывает сообщение об ошибке на stderr

11

#pragma

Выдает специальные команды компилятору с использованием стандартизированного метода

#define

Заменяет макрос препроцессора

#включают

Вставляет определенный заголовок из другого файла

#undef

Определяет макрос препроцессора

#ifdef

Возвращает true, если этот макрос определен

#ifndef

Возвращает true, если этот макрос не определен

#если

Проверяет, верно ли условие времени компиляции

#else

Альтернатива для #if

#elif

# еще #if в одном утверждении

#endif

Завершает препроцессор условно

#ошибка

Распечатывает сообщение об ошибке на stderr

#pragma

Выдает специальные команды компилятору с использованием стандартизированного метода

Примеры препроцессоров

Проанализируйте следующие примеры, чтобы понять различные директивы.

#define MAX_ARRAY_LENGTH 20

Эта директива указывает OCPP заменять экземпляры MAX_ARRAY_LENGTH на 20. Используйте #define для констант, чтобы повысить удобочитаемость.

#import <Foundation/Foundation.h>
#include "myheader.h"

Эти директивы сообщают OCPP, что нужно получить файл foundation.h из Foundation Framework и добавить текст в текущий исходный файл. Следующая строка говорит OCPP, чтобы получить myheader.h из локального каталога и добавить содержимое в текущий исходный файл.

#undef  FILE_SIZE
#define FILE_SIZE 42

Это говорит OCPP отменить определение существующего FILE_SIZE и определить его как 42.

#ifndef MESSAGE
   #define MESSAGE "You wish!"
#endif

Это говорит OCPP определять MESSAGE, только если MESSAGE еще не определен.

#ifdef DEBUG
   /* Your debugging statements here */
#endif

Это говорит OCPP, что нужно выполнить обработку вложенных операторов, если определен DEBUG. Это полезно, если вы передаете флаг -DDEBUG компилятору gcc во время компиляции. Это определит DEBUG, так что вы можете включать и выключать отладку на лету во время компиляции.

Предопределенные макросы

ANSI C определяет количество макросов. Хотя каждый из них доступен для использования в программировании, предопределенные макросы не должны изменяться напрямую.

Sr.No. Макрос и описание
1

__ДАТА__

Текущая дата в виде символьного литерала в формате «МММ ДД ГГГГ»

2

__ВРЕМЯ__

Текущее время как символьный литерал в формате «ЧЧ: ММ: СС»

3

__ФАЙЛ__

Это содержит текущее имя файла в виде строкового литерала.

4

__ЛИНИЯ__

Он содержит номер текущей строки в виде десятичной константы.

5

__STDC__

Определяется как 1, когда компилятор соответствует стандарту ANSI.

__ДАТА__

Текущая дата в виде символьного литерала в формате «МММ ДД ГГГГ»

__ВРЕМЯ__

Текущее время как символьный литерал в формате «ЧЧ: ММ: СС»

__ФАЙЛ__

Это содержит текущее имя файла в виде строкового литерала.

__ЛИНИЯ__

Он содержит номер текущей строки в виде десятичной константы.

__STDC__

Определяется как 1, когда компилятор соответствует стандарту ANSI.

Давайте попробуем следующий пример —

Live Demo

#import <Foundation/Foundation.h>

int main() {
   NSLog(@"File :%s\n", __FILE__ );
   NSLog(@"Date :%s\n", __DATE__ );
   NSLog(@"Time :%s\n", __TIME__ );
   NSLog(@"Line :%d\n", __LINE__ );
   NSLog(@"ANSI :%d\n", __STDC__ );
   
   return 0;
}

Когда приведенный выше код в файле main.m компилируется и выполняется, он дает следующий результат —

2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1

Операторы препроцессора

Препроцессор Objective-C предлагает следующие операторы, которые помогут вам в создании макросов:

Продолжение макроса (\)

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

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

Stringize (#)

Оператор stringize или number-sign (‘#’), когда используется в определении макроса, преобразует параметр макроса в строковую константу. Этот оператор может использоваться только в макросе, который имеет указанный аргумент или список параметров. Например —

Live Demo

#import <Foundation/Foundation.h>

#define  message_for(a, b)  \
   NSLog(@#a " and " #b ": We love you!\n")

int main(void) {
   message_for(Carole, Debra);
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —

2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!

Вставка токена (##)

Оператор вставки токена (##) в определении макроса объединяет два аргумента. Он позволяет объединить два отдельных токена в определении макроса в один токен. Например —

Live Demo

#import <Foundation/Foundation.h>

#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)

int main(void) {
   int token34 = 40;
   
   tokenpaster(34);
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —

2013-09-14 05:48:14.859 demo[20683] token34 = 40

Как это произошло, потому что этот пример приводит к следующему фактическому выводу препроцессора —

NSLog (@"token34 = %d", token34);

В этом примере показано объединение токена ## n в token34, и здесь мы использовали как stringize, так и вставку токена .

Определенный () оператор

Определяемый препроцессором оператор используется в константных выражениях, чтобы определить, определен ли идентификатор с помощью #define. Если указанный идентификатор определен, значение равно true (не ноль). Если символ не определен, значение равно false (ноль). Определенный оператор указан следующим образом:

Live Demo

#import <Foundation/Foundation.h>

#if !defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void) {
   NSLog(@"Here is the message: %s\n", MESSAGE);  
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —

2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!

Параметризованные макросы

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

int square(int x) {
   return x * x;
}

Мы можем переписать приведенный выше код с помощью макроса следующим образом:

#define square(x) ((x) * (x))

Макросы с аргументами должны быть определены с использованием директивы #define, прежде чем их можно будет использовать. Список аргументов заключен в круглые скобки и должен следовать сразу за именем макроса. Пробелы между именем макроса и открытыми скобками не допускаются. Например —

Live Demo

#import <Foundation/Foundation.h>

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

int main(void) {
   NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));  
   return 0;
}

Когда приведенный выше код компилируется и выполняется, он дает следующий результат —