C/Directrices para o preprocesador

En Galilibros, o Wikibooks en galego.
< C
C
← Volver a Funcións Directrices para o preprocesador


O preprocesador de C executa unha serie de instrucións antes de que comece a verdadeira compilación do programa. Estas instrucións son as directrices para o preprocesador, e son todas as liñas que comezan polo símbolo #. Estas instrucións permiten establecer condicións para a compilación ou non de fragmentos de código, incluír ficheiros con código adicional, etc. todo antes de que o código sexa compilado. As principais ordes para o preprocesador son #include e #define.

Entre as vantaxes das directrices para o precompilador están a portabilidade do código fonte ou a mellora da comprensión do código.

#define[editar]

Prefírese o uso de variables constantes no seu lugar sempre que sexa posible.

Esta orde permite realizar substitucións sistemáticas de texto ao longo dun código fonte antes de que comece a compilación. O feito de que os cambios se introduzan antes da compilación dificulta a tarefa de buscar os erros causados por ocorrencias desta directriz. A súa sintaxe fundamental é a seguinte:

#define CLAVE TEXTO

Onde:

  • CLAVE é a clave a buscar (unha soa palabra) e
  • TEXTO é a expresión que a vai substituír.

Esta orde para o preprocesador permite, por exemplo, repetir un mesmo valor numérico como constante varias veces ao longo dun mesmo código, e o máis importante, facilita a tarefa de cambiar dito valor en todo o código, reducíndoa a cambiar o valor no #define. E en caso de utilizar palabras clave descritivas, permite asemade mellorar a comprensión do código fonte. É o caso do seguinte exemplo:

#define IVE 16L
// [...]
  c = a+a*(IVE/100); // Substitúese IVE por 16L.
		 // (o «L» é para especificar o tipo de dato, “long”, do «16»)
// [...]

As palabras clave a utilizar cos #define adoitan escribirse dun xeito que se evite calquera posible coincidencia accidental. Para iso adoitan escribirse completamente en maiúsculas, e comezar cunha barra baixa, «_».

#define permite tamén definir unha clave a secas (sen asignarlle un texto de substitución), algo moi utilizado a día de hoxe para preparar o código fonte para as diferencias entre os distintos compiladores e as distintas plataformas, dado que mediante outras directrices (#ifdef ou #ifndef) pode utilizarse a definición ou non dunha clave como condición para outras directrices do preprocesador.

#define pode levar argumentos, o que permite definir dalgunha maneira funcións. Véxase o seguinte exemplo:

#define VALOR_ABSOLUTO( x ) ( ((x) < 0) ? -(x) : (x) )
// [...]
int x = -1;
if( ABSOLUTE_VALUE( x ) ) {
// [...]

Convencións respecto das definicións de claves[editar]

As seguintes convencións adoitan evitar erros frecuentes ao definir claves:

  • Cómpre colocar as variables sempre entre parénteses no texto de substitución para asegurarse de que, se son expresións, se executen coa prioridade máis alta posible para non mesturarse con outros operadores.
  • Se o texto de substitución é unha expresión, cómpre rodealo no seu conxunto de parénteses, polos mesmos motivos que no caso anterior.
  • Se o texto de substitución contén máis dunha orde ou declaracións de variables, cómpre situalo dentro dun ciclo do{ [...] } while(0), sen rematalo en «;», de xeito que poda usarse no código coma unha simple orde.
  • Cando sexa posible, evítese repetir un argumento no texto de substitución.
  • Se unha substitución desaparecerá nun futuro para deixar paso a unha función, a clave debería nomearse igualq ue a futura función.

#[editar]

O operador «#» permite que o primeiro argumento que lle siga se converta nunha cadea de texto limitada con comiñas dobres, «"». Por exemplo, a seguinte instrución:

#define COMO_CADEA( t ) # t

Convertería o seguinte código:

puts( COMO_CADEA( MI MADRIÑA! ) );

Nestoutro:

puts( "MI MADRIÑA!" );

Aproveitando a propiedade de C que di que varias cadeas de texto xuntas equivalen a unha única cadea, este operador permite inserir texto en cadeas de texto. Por exemplo, a seguinte instrución:

#define COMER( algo ) "Estou a comer " #t "."

Convertería o seguinte código:

puts( COMER( froita ) );

Nestoutro:

puts( "Estou a comer " "froita" "." ); // Interpretaríase coma unha única cadea.

##[editar]

O operador «##» concatena as variables dos seus dous extremos. Por exemplo, a seguinte instrución:

#define CONCATENAR( x, y ) x ## y

Convertería o seguinte código:

printf( "%d", CONCATENAR( x, y ));

Nestoutro:

printf( "%d", xy);

Comezo habitual dos ficheiros de cabeceira[editar]

Un uso habitual da directriz #define é para a inclusión dos ficheiros de cabeceira nos códigos fonte, pois só se deben incluír unha vez. De maneira indirecta, é habitual incluír un ficheiro varias veces, dado que moitos ficheiros de cabeceira dependen á súa vez doutros. Mediante o uso de directrices condicionais xunto co #define, pódese evitar a repetición. Para iso utilízase unha clave baseada xeralmente no propio nome do ficheiro de cabeceira. Véxase o seguinte exemplo:

#ifndef FICHEIRO_DE_CABECEIRA_H
#define FICHEIRO_DE_CABECEIRA_H
// Contido do ficheiro de cabeceira.
#endif

#error[editar]

Esta instrución detén a compilación. A súa sintaxe básica é a seguinte:

#error MENSAXE

Adoita utilizarse para a depuración de código.

#ifdef[editar]

Esta instrución analiza a expresión que lle segue, e segundo o seu valor sexa distinto de cero ou non, incluirá ou non un bloque de código. A súa sintaxe fundamental é a seguinte:

#if CONDICIÓN
// Bloque de código a incluír.
#endif

A CONDICIÓN pode conter calquera operador salvo os de asignación, incremento, redución, enderezo e sizeof().

A directriz pode combinarse con outras dúas, #elif e #else. #elif permite establecer máis bloques de código asignados a condicións dentro dun #if. #else permite establecer un bloque de código para cando non se cumpre a condición de ningún #if ou #elif. A seguinte é unha sintaxe máis completa do uso de #if:

#if CONDICIÓN1
// Código 1.
#elif CONDICIÓN2
// Código 2.
#elif CONDICIÓN3
// Código 3.
// [...]
#elif CONDICIÓNn
// Código n.
#else
// Código se non se cumpre ningunha das condicións anteriores.
#endif // Fin do #if

#ifdef[editar]

Esta orde permite establecer o que se coñece como un “grupo condicional”. Permite establecer que unha serie de instrucións só se empreguen finalmente no código fonte en caso de que unha palabra clave fose previamente definida. A súa sintaxe fundamental é a seguinte:

#ifdef CLAVE
  // Instrucións.
#endif

Entre as // Instrucións pode haber outras directrices para o preprocesador, mesmo poden aniñarse os grupos condicionais, pero de facerse ten que ser completamente. É dicir, o peche dun grupo condicional (#endif) pecha o inicio de grupo condicional inmediatamente anterior (#ifdef). Tampouco se pode distribuír un grupo condicional en ficheiros separados.

Aínda que non se definise previamente a CLAVE (e por tanto as instrucións non van estar presenten no código final), o preprocesador analizará sintacticamente as ordes do grupo condicional, polo que estas terán que seguir a sintaxe da linguaxe C de todos xeitos.

Considérase unha boa práctica indicar cun comentario ao carón do #endif cal é a clave que remata aí. Isto mellora a comprensión do código.

#ifndef[editar]

Esta orde é idéntica a #ifdef, pero o seu contido emprégase cando a CLAVE non se definiu previamente.

#include[editar]

Esta orde para o precompilador utilízase para incluír no código fonte os ficheiros de cabeceira de bibliotecas de funcións. A súa sintaxe dependerá de se o ficheiro de cabeceira en cuestión está no directorio de busca do compilador ─en cuxo caso só será necesario o nome do ficheiro─, ou noutro directorio ─en cuxo caso será necesaria a súa ruta absoluta ou relativa ao ficheiro co código fonte─. As súas sintaxes fundamentais son as seguintes:

// Biblioteca no directorio do compilador:
#include <ficheiro.h>
// Biblioteca noutro directorio:
#include "/ruta/ao/ficheiro.h"

#pragma[editar]

Incluír bibliotecas de Windows[1][editar]

Mediante a seguinte liña, substituíndo biblioteca polo nome da biblioteca en cuestión, pódese especificar en Windows unha biblioteca da que depende o código fonte. O nome da biblioteca, tal e como se amosa a continuación, debe ir delimitado por comiñas dobres (").

#pragma comment(lib, "biblioteca")

#undef[editar]

Esta directriz cancela a definición dunha clave que se definiu previamente.

Notas[editar]

  1. Blogue “I Think Tech” (en inglés).

Véxase tamén[editar]


C
← Volver a Funcións Directrices para o preprocesador