son instrucciones especiales dirigidas al preprocesador (directiva preprocesador) o al compilador (directiva compilador) sobre cómo debe procesar parte o todo su código fuente o establecer algunas banderas en el objeto final y se utilizan para facilitar la escritura del código fuente (más portátil, por ejemplo) y para hacer que el código fuente sea más comprensible. Las directivas son manejadas por el preprocesador, que es un programa separado invocado por el compilador o parte del compilador mismo.
# includeEdit
C tiene algunas características como parte del lenguaje y otras como parte de una biblioteca estándar, que es un repositorio de código que está disponible junto con todos los compiladores de C conformes con los estándares. Cuando el compilador de C compila su programa, generalmente también lo vincula con la biblioteca de C estándar. Por ejemplo, al encontrar una directiva #include <stdio.h>
, reemplaza la directiva con el contenido del stdio.archivo de cabecera h.
Cuando se utilizan funciones de la biblioteca, C requiere que se declare lo que se utilizaría. La primera línea en el programa es una directiva de preprocesamiento que debería tener este aspecto:
#include <stdio.h>
La línea anterior causa las declaraciones C que están en el stdio.encabezado h que se incluirá para su uso en su programa. Por lo general, esto se implementa simplemente insertando en su programa el contenido de un archivo de encabezado llamado stdio.h, ubicado en una ubicación dependiente del sistema. La ubicación de dichos archivos se puede describir en la documentación de su compilador. A continuación, en la tabla Encabezados, se muestra una lista de archivos de encabezado C estándar.
El stdio.el encabezado h contiene varias declaraciones para entrada/salida (E / S) utilizando una abstracción de mecanismos de E/S llamados flujos. Por ejemplo, hay un objeto de flujo de salida llamado stdout que se usa para generar texto a la salida estándar, que generalmente muestra el texto en la pantalla del ordenador.
Si se utilizan corchetes angulares como el ejemplo anterior, se indica al preprocesador que busque el archivo include a lo largo de la ruta del entorno de desarrollo para los includes estándar.
#include "other.h"
Si usa comillas ( «» ), se espera que el preprocesador busque en algunas ubicaciones adicionales, generalmente definidas por el usuario, para el archivo de encabezado, y que recurra a las rutas de inclusión estándar solo si no se encuentra en esas ubicaciones adicionales. Es común que este formulario incluya la búsqueda en el mismo directorio que el archivo que contiene la directiva # include.
NOTA: Debe verificar la documentación del entorno de desarrollo que está utilizando para cualquier implementación específica de proveedor de la directiva #include.
HeadersEdit
The C90 standard headers list:
|
|
|
Headers added since C90:
|
|
|
#pragmaEdit
La directiva pragma (información pragmática) es parte del estándar, pero el significado de cualquier pragma depende de la implementación de software del estándar que se utiliza. La directiva # pragma proporciona una forma de solicitar un comportamiento especial al compilador. Esta directiva es más útil para programas que son inusualmente grandes o que necesitan aprovechar las capacidades de un compilador en particular.
Pragmas se utilizan dentro del programa fuente.
#pragma token(s)
- pragma suele ir seguido de un único token, que representa una orden que el compilador debe obedecer. Debe verificar la implementación de software del estándar C que desea usar para obtener una lista de los tokens compatibles. No es sorprendente que el conjunto de comandos que pueden aparecer en las directivas # pragma sea diferente para cada compilador; tendrá que consultar la documentación de su compilador para ver qué comandos permite y qué hacen esos comandos.
Por ejemplo, una de las directivas de preprocesador más implementadas, #pragma once
cuando se coloca al principio de un archivo de encabezado, indica que el archivo donde reside se omitirá si el preprocesador lo incluye varias veces.
NOTA: Existen otros métodos para realizar esta acción que comúnmente se conocen como usar protectores include.
#defineEdit
ADVERTENCIA: Las macros de preprocesador, aunque tentadoras, pueden producir resultados bastante inesperados si no se hacen bien. Siempre tenga en cuenta que las macros son sustituciones textuales hechas a su código fuente antes de que se compile nada. El compilador no sabe nada de las macros y nunca llega a verlas. Esto puede producir errores oscuros, entre otros efectos negativos. Prefiera usar características de idioma, si hay equivalentes(En el ejemplo, use constantes const int
o enum
en lugar de #define
d).
Dicho esto, hay casos en los que las macros son muy útiles (consulte la macro debug
a continuación para ver un ejemplo).
La directiva #define se utiliza para definir valores o macros que el preprocesador utiliza para manipular el código fuente del programa antes de compilarlo. Debido a que las definiciones del preprocesador se sustituyen antes de que el compilador actúe sobre el código fuente, cualquier error introducido por # define es difícil de rastrear.
Por convención, los valores definidos con # define se nombran en mayúsculas. Aunque hacerlo no es un requisito, se considera muy mala práctica hacer lo contrario. Esto permite identificar fácilmente los valores al leer el código fuente.
Hoy en día, #define se utiliza principalmente para manejar las diferencias de compilador y plataforma. Por ejemplo, una definición puede contener una constante que es el código de error apropiado para una llamada al sistema. Por lo tanto, el uso de #define debe limitarse a menos que sea absolutamente necesario; las sentencias typedef y las variables constantes a menudo pueden realizar las mismas funciones de forma más segura.
Otra característica del comando # define es que puede tomar argumentos, lo que lo hace bastante útil como creador de pseudo-funciones. Considere el siguiente código:
#define ABSOLUTE_VALUE( x ) ( ((x) < 0) ? -(x) : (x) )...int x = -1;while( ABSOLUTE_VALUE( x ) ) {...}
Generalmente es una buena idea usar paréntesis adicionales cuando se usan macros complejas. Observe que en el ejemplo anterior, la variable » x » siempre está dentro de su propio conjunto de paréntesis. De esta manera, se evaluará en su totalidad, antes de compararlo con 0 o multiplicarlo por -1. Además, toda la macro está rodeada de paréntesis, para evitar que se contamine con otro código. Si no tienes cuidado, corres el riesgo de que el compilador malinterprete tu código.
Debido a los efectos secundarios, se considera una muy mala idea usar funciones macro como se describió anteriormente.
int x = -10;int y = ABSOLUTE_VALUE( x++ );
Si ABSOLUTE_VALUE () fuera una función real ‘x’ ahora tendría el valor de ‘-9’, pero debido a que era un argumento en una macro, se expandió dos veces y, por lo tanto, tiene un valor de -8.
Ejemplo:
Para ilustrar los peligros de las macros, considere esta macro ingenua
#define MAX(a,b) a>b?a:b
y el código
i = MAX(2,3)+5;j = MAX(3,2)+5;
Eche un vistazo a esto y considere cuál podría ser el valor después de la ejecución. Las instrucciones se convierten en
int i = 2>3?2:3+5;int j = 3>2?3:2+5;
Por lo tanto, después de la ejecución i=8 y j=3 en lugar del resultado esperado de i=j=8! Esta es la razón por la que se le advirtió que usara un conjunto adicional de paréntesis arriba, pero incluso con estos, el camino está lleno de peligros. El lector de alertas puede darse cuenta rápidamente de que si a
o b
contiene expresiones, la definición debe poner entre paréntesis cada uso de a,b en la definición de macro, de la siguiente manera:
#define MAX(a,b) ((a)>(b)?(a):(b))
Esto funciona, siempre que a,b no tenga efectos secundarios. De hecho,
i = 2;j = 3;k = MAX(i++, j++);
resultaría en k = 4, i=3 y j=5. Esto sería muy sorprendente para cualquiera que espere que MAX () se comporte como una función.
Entonces, ¿cuál es la solución correcta? La solución es no usar macro en absoluto. Una función global en línea, como esta
inline int max(int a, int b) { return a>b?a:b }
no tiene ninguna de las trampas anteriores, pero no funcionará con todos los tipos.
NOTA: La declaración explícita inline
no es realmente necesaria a menos que la definición esté en un archivo de encabezado, ya que su compilador puede insertar funciones para usted (con gcc esto se puede hacer con -finline-functions
o -O3
). El compilador es a menudo mejor que el programador a la hora de predecir qué funciones vale la pena insertar. Además, las llamadas a funciones no son realmente caras (solían serlo).
El compilador es libre de ignorar la palabra clave inline
. Es solo una sugerencia (excepto que inline
es necesario para permitir que una función se defina en un archivo de encabezado sin generar un mensaje de error debido a que la función se define en más de una unidad de traducción).
(#,##)
Los operadores # y ## se utilizan con la macro #define. El uso de # hace que el primer argumento después de # se devuelva como una cadena entre comillas. Por ejemplo, el comando
#define as_string( s ) # s
hará que el compilador activar este comando
puts( as_string( Hello World! ) ) ;
en
puts( "Hello World!" );
Usando ## concatena lo que antes de la ## con lo que después de él. Por ejemplo, el comando
#define concatenate( x, y ) x ## y...int xy = 10;...
hará que el compilador de vuelta
printf( "%d", concatenate( x, y ));
en
printf( "%d", xy);
que, por supuesto, mostrar 10 a la salida estándar.
Es posible concatenar un argumento de macro con un prefijo o sufijo constante para obtener un identificador válido como en
#define make_function( name ) int my_ ## name (int foo) {}make_function( bar )
que definirá una función llamada my_bar(). Pero no es posible integrar un argumento de macro en una cadena constante utilizando el operador de concatenación. Para obtener tal efecto, se puede usar la propiedad ANSI C de que dos o más constantes de cadena consecutivas se consideran equivalentes a una sola constante de cadena cuando se encuentran. Usando esta propiedad, se puede escribir
#define eat( what ) puts( "I'm eating " #what " today." )eat( fruit )
que el macro procesador convertirá en
puts( "I'm eating " "fruit" " today." )
que a su vez será interpretado por el analizador de C como una constante de cadena única.
El siguiente truco se puede usar para convertir constantes numéricas en literales de cadena
#define num2str(x) str(x)#define str(x) #x#define CONST 23puts(num2str(CONST));
Esto es un poco complicado, ya que se expande en 2 pasos. En primer lugar, num2str(CONST)
se sustituye por str(23)
, que a su vez se sustituye por "23"
. Esto puede ser útil en el siguiente ejemplo:
#ifdef DEBUG#define debug(msg) fputs(__FILE__ ":" num2str(__LINE__) " - " msg, stderr)#else#define debug(msg)#endif
Esto le dará un mensaje de depuración agradable que incluye el archivo y la línea donde se emitió el mensaje. Sin embargo, si la depuración no está definida, el mensaje de depuración desaparecerá completamente de su código. Tenga cuidado de no usar este tipo de construcción con nada que tenga efectos secundarios, ya que esto puede conducir a errores, que aparecen y desaparecen dependiendo de los parámetros de compilación.
macrosEdit
Las macros no se comprueban de tipo y, por lo tanto, no evalúan argumentos. Además, no obedecen al ámbito correctamente, sino que simplemente toman la cadena que se les pasa y reemplazan cada ocurrencia del argumento de la macro en el texto de la macro con la cadena real para ese parámetro (el código se copia literalmente en la ubicación desde la que se llamó).
Un ejemplo de cómo usar una macro:
#include <stdio.h> #define SLICES 8 #define ADD(x) ( (x) / SLICES ) int main(void) { int a = 0, b = 10, c = 6; a = ADD(b + c); printf("%d\n", a); return 0; }
the el resultado de «a» debe ser «2» (b + c = 16 -> pasado a ADD -> 16 / SLICES -> el resultado es «2»)
NOTA:
Suele ser una mala práctica definir macros en encabezados.
Una macro debe definirse solo cuando no es posible lograr el mismo resultado con una función u otro mecanismo. Algunos compiladores son capaces de optimizar el código para que las llamadas a funciones pequeñas se reemplacen con código en línea, negando cualquier posible ventaja de velocidad.El uso de typedefs, enumeraciones y en línea (en C99) suele ser una mejor opción.
Una de las pocas situaciones en las que las funciones en línea no funcionan, por lo que se ve prácticamente obligado a usar macros similares a funciones en su lugar, es inicializar constantes de tiempo de compilación (inicialización estática de estructuras).Esto sucede cuando los argumentos de la macro son literales que el compilador puede optimizar a otro literal.
#errorEdit
La directiva # error detiene la compilación. Cuando se encuentra uno, el estándar especifica que el compilador debe emitir un diagnóstico que contenga los tokens restantes en la directiva. Esto se usa principalmente para fines de depuración.
Los programadores usan «# error » dentro de un bloque condicional, para detener inmediatamente el compilador cuando el «#if» o «#ifdef» detects al principio del bloque detects detecta un problema en tiempo de compilación.Normalmente el compilador salta el bloque (y la directiva «#error» dentro de él) y la compilación procede.
#error message
#warningEdit
Muchos compiladores soportan una directiva #warning. Cuando se encuentra uno, el compilador emite un diagnóstico que contiene los tokens restantes en la directiva.
#warning message
#undefEdit
La directiva #undef desactiva una macro. No es necesario que el identificador se haya definido previamente.
#if, # else,#elif, # endif (condicionales)Edit
El comando # if comprueba si una expresión condicional de control se evalúa como cero o distinta de cero, y excluye o incluye un bloque de código, respectivamente. Por ejemplo:
#if 1 /* This block will be included */ #endif #if 0 /* This block will not be included */ #endif
La expresión condicional podría contener cualquier operador C excepto los operadores de asignación, los operadores de incremento y decremento, el operador de dirección y el operador de tamaño.
Un operador único utilizado en el preprocesamiento y en ningún otro lugar es el operador definido. Devuelve 1 si el nombre de la macro, opcionalmente encerrado entre paréntesis, está definido actualmente; 0 si no.
El #endif comando termina un bloque iniciado por #if
#ifdef
o #ifndef
.
El comando #elif es similar a #if
, excepto que se usa para extraer uno de una serie de bloques de código. Por ejemplo:
#if /* some expression */ : : : #elif /* another expression */ : /* imagine many more #elifs here ... */ : #else /* The optional #else block is selected if none of the previous #if or #elif blocks are selected */ : : #endif /* The end of the #if block */
#ifdef,#ifndefEdit
El comando #ifdef es similar a #if
, excepto que el bloque de código que lo sigue se selecciona si se define un nombre de macro. A este respecto,
#ifdef NAME
es equivalente a
#if defined NAME
El comando #ifndef es similar a #ifdef, excepto que la prueba se invierte:
#ifndef NAME
es equivalente a
#if !defined NAME
#LineEdit
Esta directiva de preprocesador se utiliza para establecer el nombre de archivo y el número de línea de la línea que sigue a la directiva en valores nuevos. Esto se usa para establecer las macros __FILE__ y __LINE__.