Preprocesadores Objective-C

los Objective-C Preprocessorno es parte del compilador, pero es un paso separado en el proceso de compilación. En términos simplistas, un preprocesador de Objective-C es solo una herramienta de sustitución de texto e indica al compilador que realice el preprocesamiento requerido antes de la compilación real. Nos referiremos al preprocesador de Objective-C como OCPP.

Todos los comandos del preprocesador comienzan con un símbolo de almohadilla (#). Debe ser el primer carácter que no esté en blanco y, para facilitar la lectura, una directiva de preprocesador debe comenzar en la primera columna. La siguiente sección enumera todas las directivas importantes del preprocesador:

No Señor. Directiva y descripción
1

#define

Sustituye a una macro de preprocesador

2

#include

Inserta un encabezado particular de otro archivo

3

#undef

Elimina la definición de una macro de preprocesador

4

#ifdef

Devuelve verdadero si esta macro está definida

5

#ifndef

Devuelve verdadero si esta macro no está definida

6

#if

Prueba si una condición de tiempo de compilación es verdadera

7

#else

La alternativa para #if

8

#elif

#else an #if in one statement

9

#endif

Finaliza el preprocesador condicional

10

#error

Imprime mensaje de error en stderr

11

#pragma

Emite comandos especiales al compilador mediante un método estandarizado

Ejemplos de preprocesadores

Analice los siguientes ejemplos para comprender varias directivas.

#define MAX_ARRAY_LENGTH 20

Esta directiva le dice al OCPP que reemplace las instancias de MAX_ARRAY_LENGTH con 20. Use #define para constantes para aumentar la legibilidad.

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

Estas directivas le dicen al OCPP que obtenga foundation.h de Foundation Frameworky agregue el texto al archivo fuente actual. La siguiente línea le dice a OCPP que obtengamyheader.h del directorio local y agregue el contenido al archivo fuente actual.

#undef  FILE_SIZE
#define FILE_SIZE 42

Esto le dice al OCPP que anule la definición de FILE_SIZE existente y lo defina como 42.

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

Esto le dice al OCPP que defina MESSAGE solo si MESSAGE aún no está definido.

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

Esto le dice al OCPP que procese las declaraciones adjuntas si se define DEBUG. Esto es útil si pasa el indicador -DDEBUG al compilador gcc en el momento de la compilación. Esto definirá DEBUG, por lo que puede activar y desactivar la depuración sobre la marcha durante la compilación.

Macros predefinidas

ANSI C define una serie de macros. Aunque cada uno está disponible para su uso en programación, las macros predefinidas no deben modificarse directamente.

No Señor. Macro y descripción
1

__DATE__

La fecha actual como un carácter literal en formato "MMM DD AAAA"

2

__TIME__

La hora actual como un carácter literal en formato "HH: MM: SS"

3

__FILE__

Contiene el nombre del archivo actual como una cadena literal.

4

__LINE__

Contiene el número de línea actual como una constante decimal.

5

__STDC__

Definido como 1 cuando el compilador cumple con el estándar ANSI.

Probemos con el siguiente ejemplo:

#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;
}

Cuando el código anterior en un archivo main.m se compila y ejecuta, produce el siguiente resultado:

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

Operadores de preprocesadores

El preprocesador de Objective-C ofrece los siguientes operadores para ayudarlo a crear macros:

Continuación macro (\)

Por lo general, una macro debe estar contenida en una sola línea. El operador de continuación de macro se utiliza para continuar una macro que es demasiado larga para una sola línea. Por ejemplo

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

Stringize (#)

El operador de cadena o signo de número ('#'), cuando se utiliza dentro de una definición de macro, convierte un parámetro de macro en una constante de cadena. Este operador solo se puede utilizar en una macro que tenga un argumento o una lista de parámetros especificados. Por ejemplo

#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;
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

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

Pegado de tokens (##)

El operador de pegado de tokens (##) dentro de una definición de macro combina dos argumentos. Permite que dos tokens separados en la definición de macro se unan en un solo token. Por ejemplo

#import <Foundation/Foundation.h>

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

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

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

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

Cómo sucedió, porque este ejemplo da como resultado la siguiente salida real del preprocesador:

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

Este ejemplo muestra la concatenación del token ## n en token34 y aquí hemos usado ambos stringize y token-pasting.

El operador definido ()

El preprocesador definedEl operador se usa en expresiones constantes para determinar si un identificador se define usando #define. Si se define el identificador especificado, el valor es verdadero (distinto de cero). Si el símbolo no está definido, el valor es falso (cero). El operador definido se especifica de la siguiente manera:

#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;
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

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

Macros parametrizados

Una de las poderosas funciones del OCPP es la capacidad de simular funciones utilizando macros parametrizadas. Por ejemplo, podríamos tener algún código para elevar al cuadrado un número de la siguiente manera:

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

Podemos reescribir el código anterior usando una macro de la siguiente manera:

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

Las macros con argumentos deben definirse utilizando el #definedirectiva antes de que se puedan utilizar. La lista de argumentos está entre paréntesis y debe seguir inmediatamente al nombre de la macro. No se permiten espacios entre el nombre de la macro y el paréntesis abierto. Por ejemplo

#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;
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20