Entendiendo el Preprocesador de C (CPP): Cómo Simplifica la Compilación
El preprocesador de C no forma parte del compilador, sino que es un paso separado en el proceso de compilación. En términos sencillos, el preprocesador de C es simplemente una herramienta de sustitución de texto que indica al compilador que realice el preprocesamiento necesario antes de la compilación propiamente dicha. Nos referiremos al preprocesador de C como CPP.
Directivas del Preprocesador
Todos los comandos del preprocesador comienzan con el símbolo de almohadilla (#). Debe ser el primer carácter no en blanco y, para facilitar la lectura, una directiva del preprocesador debería comenzar en la primera columna. A continuación se enumeran las directivas más importantes:
| Nº | Directiva y Descripción |
|---|---|
| 1 | #define Sustituye un macro del preprocesador. |
| 2 | #include Inserta un archivo de cabecera específico desde otro archivo. |
| 3 | #undef Anula la definición de un macro del preprocesador. |
| 4 | #ifdef Devuelve verdadero si el macro está definido. |
| 5 | #ifndef Devuelve verdadero si el macro no está definido. |
| 6 | #if Comprueba si una condición en tiempo de compilación es verdadera. |
| 7 | #else Alternativa para #if. |
| 8 | #elif Combina #else y #if en una sola sentencia. |
| 9 | #endif Finaliza una condicional del preprocesador. |
| 10 | #error Imprime un mensaje de error en la salida estándar de error. |
| 11 | #pragma Emite comandos especiales al compilador mediante un método estandarizado. |
Ejemplos de Preprocesador
Analice los siguientes ejemplos para comprender las distintas directivas.
#define MAX_ARRAY_LENGTH 20
Esta directiva indica al CPP que reemplace las apariciones de MAX_ARRAY_LENGTH por 20. Utilice #define para constantes con el fin de mejorar la legibilidad.
#include <stdio.h>
#include "myheader.h"
Estas directivas ordenan al CPP obtener stdio.h de las bibliotecas del sistema e insertar su contenido en el archivo fuente actual. La siguiente línea indica al CPP que obtenga myheader.h del directorio local y añada su contenido.
#undef FILE_SIZE
#define FILE_SIZE 42
Indica al CPP que anule la definición existente de FILE_SIZE y la defina como 42.
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
Indica al CPP que defina MESSAGE solo si no está definido ya.
#ifdef DEBUG
/* Sus sentencias de depuración aquí */
#endif
Indica al CPP que procese las sentencias incluidas si DEBUG está definido. Esto resulta útil si pasa la opción -DDEBUG al compilador gcc en el momento de la compilación; definirá DEBUG, permitiendo activar o desactivar la depuración sobre la marcha.
Macros Predefinidos
ANSI C define una serie de macros. Aunque cada uno está disponible para su uso en la programación, los macros predefinidos no deben modificarse directamente.
| Nº | Macro y Descripción |
|---|---|
| 1 | __DATE__ La fecha actual como literal de cadena en formato "MMM DD AAAA". |
| 2 | __TIME__ La hora actual como literal de cadena en formato "HH:MM:SS". |
| 3 | __FILE__ Contiene el nombre del archivo actual como literal de cadena. |
| 4 | __LINE__ Contiene el número de línea actual como constante decimal. |
| 5 | __STDC__ Definido como 1 cuando el compilador cumple el estándar ANSI. |
Probemos el siguiente ejemplo:
#include <stdio.h>
int main() {
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
printf("ANSI :%d\n", __STDC__ );
}
Cuando el código anterior, en un archivo test.c, se compila y ejecuta, produce el siguiente resultado:
File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1
Operadores del Preprocesador
El preprocesador de C ofrece los siguientes operadores para ayudar a crear macros:
Operador de Continuación de Macro (\)
Un macro normalmente se limita a una sola línea. El operador de continuación (\) se utiliza para extender un macro que es demasiado largo para una sola línea. Por ejemplo:
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
Operador de Conversión a Cadena (#)
El operador de conversión a cadena (#), cuando se usa dentro de una definición de macro, convierte un parámetro del macro en una constante de cadena. Este operador solo puede usarse en un macro que tenga una lista de argumentos especificada. Por ejemplo:
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
Al compilar y ejecutar el código anterior, se obtiene:
Carole and Debra: We love you!
Operador de Concatenación de Tokens (##)
El operador de concatenación de tokens (##) dentro de una definición de macro combina dos argumentos. Permite que dos tokens separados en la definición del macro se unan en un solo token. Por ejemplo:
#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
Al compilar y ejecutar, produce:
token34 = 40
Esto ocurre porque el ejemplo resulta en la siguiente salida real del preprocesador:
printf ("token34 = %d", token34);
Este ejemplo muestra la concatenación de token##n en token34 y aquí hemos usado tanto la conversión a cadena como la concatenación de tokens.
Operador defined()
El operador defined del preprocesador se usa en expresiones constantes para determinar si un identificador está definido mediante #define. Si el identificador especificado está definido, el valor es verdadero (distinto de cero). Si el símbolo no está definido, el valor es falso (cero). El operador defined se especifica de la siguiente forma:
#include <stdio.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
printf("Here is the message: %s\n", MESSAGE);
return 0;
}
Al compilar y ejecutar, produce:
Here is the message: You wish!
Macros con Parámetros
Una de las funciones potentes del CPP es la capacidad de simular funciones usando macros con parámetros. Por ejemplo, podríamos tener código para elevar un número al cuadrado:
int square(int x) {
return x * x;
}
Podemos reescribir el código anterior usando un macro así:
#define square(x) ((x) * (x))
Los macros con argumentos deben definirse usando la directiva #define antes de poder usarse. La lista de argumentos se encierra entre paréntesis y debe seguir inmediatamente al nombre del macro. No se permiten espacios entre el nombre del macro y el paréntesis de apertura. Por ejemplo:
#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
Al compilar y ejecutar, produce:
Max between 20 and 10 is 20
Lenguaje C
- C# Hola Mundo – Construyendo su primera aplicación en C#
- Entendiendo palabras clave e identificadores en C#: Reglas, listas y mejores prácticas
- Domine variables y tipos de datos primitivos en C#: Guía completa
- Operadores en C# – Guía completa de operadores en C#
- Dominando operadores bit a bit y de desplazamiento en C#: Guía completa
- Fundamentos de C#: Entrada y salida esenciales
- Expresiones, sentencias y bloques en C#: Guía completa con ejemplos prácticos
- Dominando los comentarios en C#: Tipos, mejores prácticas y documentación XML
- Dominando la sentencia switch en C#: Sintaxis, ejemplos y mejores prácticas
- Operador ternario en C#: Guía concisa para expresiones condicionales
- Sentencia break en C#: Cómo y cuándo usarla