← C EspañolChapter 11 of 13

Directivas del Preprocesador

## Objetivos de Aprendizaje - Comprender el preprocesador de C - Dominar directivas de inclusión - Trabajar con macros - Usar compilación condicional ## Descripción General del Preprocesador El preprocesador se ejecuta antes de la compilación, transformando el código fuente. ```c #define PI 3.14159 ``` Se convierte en: ```c 3.14159 ``` ## Directivas de Inclusión ### #include ```c #include // Encabezado del sistema #include "myheader.h" // Encabezado del usuario ``` ### Guardas de Inclusión ```c // myheader.h #ifndef MYHEADER_H #define MYHEADER_H // Contenido del encabezado #endif ``` ### #pragma once (Moderno) ```c // myheader.h #pragma once // Contenido del encabezado ``` ## Definición de Macros ### Macros Tipo Objeto ```c #define PI 3.14159 #define MAX_SIZE 100 #define TRUE 1 #define FALSE 0 ``` ### Macros Tipo Función ```c #define SQUARE(x) ((x) * (x)) int result = SQUARE(5); // 25 ``` ### Múltiples Argumentos ```c #define MAX(a, b) ((a) > (b) ? (a) : (b)) int m = MAX(10, 20); // 20 ``` ### ¿Por Qué Usar Paréntesis? ```c // Sin paréntesis #define SQUARE(x) x * x int result = SQUARE(5); // 25 (correcto) int result = SQUARE(2 + 3); // 2 + 3 * 2 + 3 = 11 (¡INCORRECTO!) // Con paréntesis #define SQUARE(x) ((x) * (x)) int result = SQUARE(2 + 3); // ((2 + 3) * (2 + 3)) = 25 (correcto) ``` ## Concatenación de Tokens ### Operador de Concatenación de Tokens ```c #define CONCAT(a, b) a ## b int xy = 10; CONCAT(x, y); // Se expande a xy ``` ## Stringificación ### Operador de Stringificación ```c #define PRINT_INT(x) printf(#x " = %d\n", x) int value = 42; PRINT_INT(value); // Se expande a: // printf("value" " = %d\n", value); ``` ## Compilación Condicional ### #ifdef / #ifndef ```c #define DEBUG 1 #ifdef DEBUG printf("Debug mode\n"); #endif #ifndef PI #define PI 3.14159 #endif ``` ### #if / #else / #elif ```c #if __STDC_VERSION__ >= 201112L // C11 o posterior printf("C11 or later\n"); #elif __STDC_VERSION__ >= 199901L // C99 printf("C99\n"); #else // C89/C90 printf("C89/C90\n"); #endif ``` ### Operador Defined ```c #if defined(DEBUG) && DEBUG > 0 printf("Debug level: %d\n", DEBUG); #endif // Forma corta: #if defined(DEBUG) // ... #endif // Forma aún más corta: #ifdef DEBUG // ... #endif ``` ## Macros Predefinidas | Macro | Descripción | |-------|-------------| | `__FILE__` | Nombre del archivo actual | | `__LINE__` | Número de línea actual | | `__DATE__` | Fecha de compilación | | `__TIME__` | Hora de compilación | | `__STDC__` | Conformidad con ISO C | | `__STDC_VERSION__` | Versión del estándar C | | `__func__` | Nombre de la función actual | ```c #include int main(void) { printf("File: %s\n", __FILE__); printf("Line: %d\n", __LINE__); printf("Date: %s\n", __DATE__); printf("Time: %s\n", __TIME__); printf("Function: %s\n", __func__); return 0; } ``` ## Macro Assert ```c #include int divide(int a, int b) { assert(b != 0); // Falla si b es 0 return a / b; } ``` ### Desactivar Aserciones ```c #define NDEBUG // Desactivar aserciones #include ``` ## Macros Variádicos ```c #define DEBUG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) DEBUG("Error %d: %s\n", errno, strerror(errno)); ``` ### Argumento Variádico Vacío ```c #define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) LOG("Hello\n"); // Funciona LOG("Value: %d\n", 42); // Funciona ``` ## Eliminar Macros ```c #define PI 3.14159 printf("%f\n", PI); #undef PI #define PI 3.14 // Ahora se permite redefinir ``` ## Operadores del Preprocesador ### #pragma ```c #pragma pack(push, 1) struct Packed { char c; int x; }; #pragma pack(pop) ``` ### _Pragma ```c _Pragma("pack(push, 1)") struct Packed { char c; int x; }; _Pragma("pack(pop)") ``` ## Patrones Comunes ### Guardas de Encabezado ```c // math_utils.h #ifndef MATH_UTILS_H #define MATH_UTILS_H int add(int a, int b); int subtract(int a, int b); #endif ``` ### Detección de Plataforma ```c #ifdef _WIN32 // Windows #include #elif __linux__ // Linux #include #elif __APPLE__ // macOS #include #endif ``` ### Prueba de Características ```c #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L // Usar funciones POSIX #endif ``` ### Registro de Depuración ```c #define DEBUG #ifdef DEBUG #define LOG(fmt, ...) fprintf(stderr, "[%s:%d] " fmt "\n", \ __FILE__, __LINE__, ##__VA_ARGS__) #else #define LOG(fmt, ...) // Vacío en producción #endif ``` ### Obsolescencia ```c #define DEPRECATED __attribute__((deprecated)) DEPRECATED void oldFunction(void) { // ... } ``` ## Macro vs Función | Aspecto | Macro | Función | |---------|-------|----------| | Velocidad | Más rápida (sin sobrecarga de llamada) | Más lenta | | Tipo | Genérica (sustitución de texto) | Tipo-seguro | | Depuración | Más difícil | Más fácil | | Argumentos | Evaluados en cada uso | Evaluados una vez | ## Resumen - El preprocesador se ejecuta antes de la compilación - `#include` incluye archivos de encabezado - Usar guardas de inclusión o `#pragma once` - `#define` crea macros - Las macros de función deben usar paréntesis - `#ifdef`/`#if` para compilación condicional - Macros predefinidas: `__FILE__`, `__LINE__`, `__DATE__` - `NDEBUG` desactiva aserciones - Macros variádicos: `__VA_ARGS__`

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →