C Preprocesador
Preprocesador de C (CPP)Es una etapa independiente en el proceso de compilación, antes dela compilación realRealiza el procesamiento de texto del código fuente. Las funciones principales incluyen:
- Expansión de macros
- Inclusión de archivos
- Compilación condicional
- Procesamiento de directivas especiales
El preprocesador de CNo es parte del compilador, pero es un paso separado en el proceso de compilación.
En resumen, el preprocesador de C no es más que una herramienta de reemplazo de texto; indica al compilador que realice el preprocesamiento necesario antes de la compilación real.
Abreviaremos el preprocesador de C (C Preprocessor) como CPP.
Todos los comandos del preprocesador comienzan con el símbolo de almohadilla#al principio. Debe ser el primer carácter que no sea un espacio en blanco. Para mejorar la legibilidad, las directivas del preprocesador deben comenzar en la primera columna.
A continuación se enumeran todas las directivas importantes del preprocesador:
| Directiva | Descripción | Ejemplo de uso |
|---|---|---|
#define |
Define una macro (constante simbólica o macro de función) | #define PI 3.14159#define MAX(a,b) ((a) > (b) ? (a) : (b)) |
#include |
Incluye un archivo de cabecera | #include <stdio.h>#include "myheader.h" |
#undef |
Cancela la definición de una macro | #undef PI |
#ifdef |
Compila el código siguiente si la macro está definida | #ifdef DEBUGprintf("Debug info\n");#endif |
#ifndef |
Compila el código siguiente si la macro no está definida (se usa a menudo para la protección de archivos de cabecera) | #ifndef HEADER_H#define HEADER_H/* contenido */#endif |
#if |
Compilación condicional (se puede usar con el operador defined) | #if VERSION > 2/* código de la nueva versión */#endif |
#else |
#if/#ifdef/#ifndefRama alternativa |
#ifdef WIN32/* Windows代码 */#else/* otros sistemas */#endif |
#elif |
Similar a else if | #if defined(UNIX)/* Unix代码 */#elif defined(WIN32)/* Windows代码 */#endif |
#endif |
Finaliza el bloque de compilación condicional | Como se muestra en el ejemplo anterior |
#error |
Genera un error de compilación y muestra un mensaje | #if !defined(C99)#error "需要C99标准"#endif |
#pragma |
Directivas específicas del compilador (no estándar, varían según el compilador) | #pragma once#pragma pack(1) |
Ejemplo de preprocesador
Analiza el siguiente ejemplo para comprender las diferentes directivas.
#define MAX_ARRAY_LENGTH 20
Esta directiva le indica a CPP que defina todas las MAX_ARRAY_LENGTH como 20. Use#definela definición de constantes para mejorar la legibilidad.
#include <stdio.h> #include "myheader.h"
Estas directivas le indican a CPP que obtenga dela biblioteca del sistemaobtenga stdio.h, y agregue el texto al archivo fuente actual. La siguiente línea le indica a CPP que obtenga del directorio localmyheader.h, y agregue su contenido al archivo fuente actual.
#undef FILE_SIZE #define FILE_SIZE 42
Esta directiva le indica a CPP que cancele la definición de FILE_SIZE y lo defina como 42.
#ifndef MESSAGE #define MESSAGE "You wish!" #endif
Esta directiva le indica a CPP que defina MESSAGE solo si MESSAGE no está definido.
#ifdef DEBUG /* Your debugging statements here */ #endif
Esta directiva le indica a CPP que, si DEBUG está definido, ejecute las declaraciones de procesamiento. Al compilar, si le pasa al compilador gcc-DDEBUGel indicador, esta directiva es muy útil. Define DEBUG y usted puede activar o desactivar la depuración en cualquier momento durante la compilación.
Ejemplo
// Definir una macro constante
#define PI 3.1415926
#define GREETING "Hello, World!"
// Definir una macro de función (presta atención al uso de paréntesis)
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
// Ejemplo de compilación condicional
#define DEBUG 1
int main() {
// Usar la macro constante
printf("El valor de PI: %f\n", PI);
printf("%s\n", GREETING);
"El cuadrado de %d es: %d
int x = 5;
printf("El mayor de 3 y 5 es: %d\n", x, SQUARE(x));
printf(// Ejemplo de compilación condicional\n", MAX(3, 5));
"[Información de depuración] El programa llegó a la función main
#ifdef DEBUG
printf(// Verificación de la versión del compilador\n");
#endif
"Usando el estándar C11
#if __STDC_VERSION__ >= 201112L
printf("Usando el estándar C99\n");
#elif __STDC_VERSION__ >= 199901L
printf("Usando el estándar C89/C90\n");
#else
printf(// Ejemplo de directiva de error (descomentar provocará un error de compilación)\n");
#endif
// #error "Este es un error activado manualmente"
Recomendaciones de mejores prácticas
return 0;
}
Recomendaciones de mejores prácticas
-
Usar letras mayúsculas y guiones bajos para nombrar macros:
- Ejemplo:
- Consideraciones sobre las macros de función
#define MAX_SIZE 100
-
Cada parámetro y la expresión completa deben ir entre paréntesis:
- Evite usar argumentos con efectos secundarios (por ejemplo,
- Protección de archivos de cabecera
SQUARE(x++))
-
Depuración con compilación condicional:
#ifndef MY_HEADER_H #define MY_HEADER_H /* 头文件内容 */ #endif
-
Desarrollo multiplataforma:
#ifdef DEBUG #define DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINT(fmt, ...) #endif
-
Macros predefinidas:
#if defined(_WIN32) // Windows特定代码 #elif defined(__linux__) // Linux特定代码 #elif defined(__APPLE__) // macOS特定代码 #endif
Macros predefinidas
Descripción
| macro | Fecha actual, una constante de caracteres en el formato "MMM DD YYYY". |
|---|---|
| __DATE__ | Hora actual, una constante de caracteres en el formato "HH:MM:SS". |
| __TIME__ | Esto contiene el nombre del archivo actual, una constante de cadena. |
| __FILE__ | Esto contiene el número de línea actual, una constante decimal. |
| __LINE__ | Se define como 1 cuando el compilador compila con el estándar ANSI. |
| __STDC__ | Probemos el siguiente ejemplo: |
Ejemplo
Ejemplo
) se compila y se ejecuta, produce el siguiente resultado:test.cOperadores del preprocesador
当前文件: predef_macros.c 编译日期: Jul 5 2023 编译时间: 14:30:45 当前行号: 13 ANSI标准: 1 [调试信息] predef_macros.c (第16行) 编译于 Jul 5 2023 14:30:45
Operadores del preprocesador
Operador de continuación de macro (\)
Operador de continuación de macro (\)
Operador de conversión a cadena (#)
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
En la definición de una macro, cuando es necesario convertir un parámetro de la macro en una constante de cadena, se usa el operador de conversión a cadena (#). Este operador, usado en una macro, tiene un parámetro específico o una lista de parámetros. Por ejemplo:
Ejemplo
Ejemplo
Operador de pegado de tokens (##)
Carole and Debra: We love you!
Operador de pegado de tokens (##)
Ejemplo
Ejemplo
Esto sucede porque este ejemplo produce la siguiente salida real del compilador:
token34 = 40
Este ejemplo demuestra que token##n se concatena para formar token34, donde hemos usado
printf ("token34 = %d", token34);
el operador de conversión a cadena (#)y el operador de pegado de tokens (##)yOperador defined()。
Operador defined()
se usa en expresiones constantes, para determinar si un identificador ya ha sido definido con #define. Si el identificador especificado está definido, el valor es verdadero (distinto de cero). Si el identificador especificado no está definido, el valor es falso (cero). El siguiente ejemplo demuestra el uso del operador defined():definedEjemplo
Ejemplo
Macros parametrizadas
Here is the message: You wish!
Macros parametrizadas
Podemos reescribir el código anterior usando una macro, de la siguiente manera:
int square(int x) {
return x * x;
}
Antes de usar una macro con parámetros, debe usar
#define square(x) ((x) * (x))
la directiva #define para definirla. La lista de parámetros se encierra entre paréntesis y debe ir inmediatamente después del nombre de la macro. No se permite ningún espacio entre el nombre de la macro y el paréntesis izquierdo. Por ejemplo:#defineEjemplo
Ejemplo
Otras extensiones
Max between 20 and 10 is 20AI pensando...