De Programação C/diretivas de pré-processamento e macros

Diretivas são instruções especiais direcionadas para o pré-processador (directiva de pré-processador) ou compilador (compilador directiva) sobre como deve ser o processo todo, ou parte, do seu código-fonte ou conjunto de algumas bandeiras sobre o objeto final e são usados para tornar a escrita de código fonte mais fácil (mais portátil, por exemplo), e tornar o código fonte mais compreensível. As diretivas são tratadas pelo pré-processador, que é um programa separado invocado pelo compilador ou parte do próprio compilador.

#includeEdit

c tem algumas características como parte da linguagem e algumas outras como parte de uma biblioteca padrão, que é um repositório de código que está disponível ao lado de cada compilador C padrão. Quando o compilador C compila o seu programa, ele geralmente também o liga com a biblioteca C padrão. Por exemplo, ao encontrar uma directiva#include <stdio.h>, substitui a directiva pelo conteúdo do stdio.ficheiro header h.

Quando você usa recursos da biblioteca, C requer que você declare o que você estaria usando. A primeira linha do programa é uma diretiva de pré-processamento que deve ser semelhante a esta:

#include <stdio.h>

a linha acima causa as declarações C que estão no stdio.cabeçalho h a ser incluído para uso em seu programa. Normalmente, isto é implementado apenas inserindo em seu programa o conteúdo de um arquivo header chamado stdio.h, localizado num local dependente do sistema. A localização desses arquivos pode ser descrita na documentação do seu compilador. Uma lista de arquivos de cabeçalho padrão C está listada abaixo na tabela Headers.

O stdio.o cabeçalho h contém várias declarações para entrada/saída (I/O) usando uma abstração de mecanismos de I/O chamados streams. Por exemplo, há um objeto de fluxo de saída chamado stdout que é usado para enviar texto para a saída padrão, que normalmente exibe o texto na tela do computador.

Se usar parêntesis de ângulo como o exemplo acima, o pré-processador é instruído a procurar o ficheiro include ao longo do Caminho do ambiente de desenvolvimento para o padrão inclui.

#include "other.h"

Se você usar aspas ( “” ), espera-se que o pré-processador procure em alguns locais adicionais, geralmente definidos pelo Usuário, para o arquivo header, e para voltar para o padrão incluir caminhos apenas se não for encontrado nesses locais adicionais. É comum este formulário incluir a pesquisa no mesmo diretório que o arquivo contendo a diretiva # include.

nota: você deve verificar a documentação do ambiente de desenvolvimento que você está usando para qualquer implementação específica do Fornecedor da diretiva #include.

HeadersEdit

The C90 standard headers list:

  • <assert.h>
  • <ctype.h>
  • <errno.h>
  • <float.h>
  • <limits.h>
  • <locale.h>
  • <math.h>
  • <setjmp.h>
  • <signal.h>
  • <stdarg.h>
  • <stddef.h>
  • <stdio.h>
  • <stdlib.h>
  • <string.h>
  • <time.h>

Headers added since C90:

  • <complex.h>
  • <fenv.h>
  • <inttypes.h>
  • <iso646.h>
  • <stdbool.h>
  • <stdint.h>
  • <tgmath.h>
  • <wchar.h>
  • <wctype.h>

#pragmaEdit

O pragma (informação pragmática) directiva é parte da norma, mas o significado de qualquer pragma depende da implementação de software de padrão que é usada. A diretiva # pragma fornece uma maneira de solicitar um comportamento especial do compilador. Esta diretiva é mais útil para programas que são invulgarmente grandes ou que precisam tirar proveito das capacidades de um compilador particular.

Pragmas são usados dentro do programa fonte.

#pragma token(s)
  1. pragma é geralmente seguido por um único token, que representa um comando para o compilador obedecer. Você deve verificar a implementação de software do padrão C que você pretende usar para uma lista dos tokens suportados. Não surpreendentemente, o conjunto de comandos que podem aparecer nas diretivas #pragma é diferente para cada compilador; você terá que consultar a documentação para seu compilador para ver quais comandos ele permite e o que esses comandos fazem.

Por exemplo, uma das directivas do pré-processador mais implementadas, #pragma once quando colocado no início de um ficheiro de cabeçalho, indica que o ficheiro onde reside será ignorado se for incluído várias vezes pelo pré-processador.

Nota: Existem outros métodos para fazer esta ação que é comumente referido como usando incluem guardas.

#defineEdit

aviso: macros pré-processador, embora tentador, pode produzir resultados bastante inesperados se não for bem feito. Tenha sempre em mente que macros são substituições textuais feitas ao seu código fonte antes de qualquer coisa ser compilada. O compilador não sabe nada sobre as macros e nunca consegue vê-las. Isto pode produzir erros obscuros, entre outros efeitos negativos. Preferir usar recursos de linguagem, se houver equivalente (em exemplo, use const int ou enum em vez de #defineconstantes d).

dito isto, existem casos em que macros são muito úteis (veja o debug macro abaixo, por exemplo).

a diretiva # define é usada para definir valores ou macros que são usados pelo pré-processador para manipular o código fonte do programa antes que ele seja compilado. Como as definições de pré-processador são substituídas antes do compilador agir no código fonte, quaisquer erros que são introduzidos por #define são difíceis de rastrear.

Por convenção, os valores definidos usando # define são nomeados em maiúsculas. Embora tal não seja um requisito, considera-se que é uma prática muito má fazer o contrário. Isso permite que os valores sejam facilmente identificados ao ler o código fonte.

hoje em dia, #define é usado principalmente para lidar com diferenças de compilador e plataforma. Por exemplo, uma definição pode conter uma constante que é o código de erro apropriado para uma chamada de Sistema. O uso de #define deve, portanto, ser limitado a menos que absolutamente necessário; declarações tipadasef e variáveis constantes podem muitas vezes executar as mesmas funções com mais segurança.

outra característica do comando # define é que ele pode tomar argumentos, tornando-o bastante útil como um criador de pseudo-função. Considere o seguinte código::

#define ABSOLUTE_VALUE( x ) ( ((x) < 0) ? -(x) : (x) )...int x = -1;while( ABSOLUTE_VALUE( x ) ) {...}

é geralmente uma boa ideia usar parêntesis extra ao usar macros complexos. Observe que no exemplo acima, a variável “x” está sempre dentro de seu próprio conjunto de parênteses. Desta forma, será avaliado em conjunto, antes de ser comparado a 0 ou multiplicado por -1. Além disso, toda a macro está rodeada de parênteses, para evitar que seja contaminada por outro código. Se não tiveres cuidado, corres o risco de o compilador interpretar mal o teu código.por causa dos efeitos secundários, é considerado uma péssima ideia usar funções macro como descrito acima.

Se ABSOLUTE_VALUE() fosse uma função real ‘ x ‘teria agora o valor de ‘-9’, mas porque era um argumento numa macro foi expandido duas vezes e, portanto, tem um valor de -8.

Exemplo:

Para ilustrar os perigos de macros, considere este ingênuo macro

#define MAX(a,b) a>b?a:b

e o código

i = MAX(2,3)+5;j = MAX(3,2)+5;

dê uma olhada neste e considerar que o valor após a execução pode ser. As declarações são transformadas em

int i = 2>3?2:3+5;int j = 3>2?3:2+5;

assim, após a execução i=8 e j=3 em vez do resultado esperado de i=j=8! É por isso que você foi advertido para usar um conjunto extra de parênteses acima, mas mesmo com estes, a estrada está cheia de perigos. O alerta leitor pode perceber rapidamente o que se a ou b contém expressões, a definição deve parenthesize cada uso de a,b, na definição de macro, como este:

#define MAX(a,b) ((a)>(b)?(a):(b))

Isto funciona, desde que a,b não têm efeitos colaterais. De fato,

i = 2;j = 3;k = MAX(i++, j++);

resultaria em k=4, i=3 e j=5. Isto seria altamente surpreendente para qualquer um que espera MAX () para se comportar como uma função.qual é então a solução correcta? A solução não é usar macro de todo. A global, inline function, like this

inline int max(int a, int b) { return a>b?a:b }

has none of the pitfalls above, but will not work with all types.

NOTA: O explícito inline declaração não é realmente necessário, a menos que a definição está em um arquivo de cabeçalho, uma vez que o compilador pode funções embutidas para você (com gcc isso pode ser feito com -finline-functions ou -O3). O compilador é muitas vezes melhor do que o programador em prever quais funções são dignas de destaque. Além disso, chamadas de funções não são realmente caros (eles costumavam ser).

O compilador é realmente livre para ignorar a palavra-chave inline. É apenas uma dica (exceto que inline é necessário para permitir que uma função seja definida em um arquivo de cabeçalho sem gerar uma mensagem de erro devido à função ser definida em mais de uma unidade de tradução).

(#,##)

the # and ## operators are used with the # define macro. O uso de # faz com que o primeiro argumento após o # seja retornado como uma string entre aspas. Por exemplo, o comando

#define as_string( s ) # s

fará com que o compilador rode este comando

puts( as_string( Hello World! ) ) ;

em

puts( "Hello World!" );

Usando ## concatena o que é antes de ## com o que está depois dela. Por exemplo, o comando

#define concatenate( x, y ) x ## y...int xy = 10;...

fará com que o compilador ativar

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

em

printf( "%d", xy);

o que, é claro, apresentar 10 para a saída padrão.

é possível concatenar um argumento de macro com uma constante de prefixo ou sufixo para obter um identificador válido como em

#define make_function( name ) int my_ ## name (int foo) {}make_function( bar )

o que vai definir uma função chamada my_bar(). Mas não é possível integrar um argumento macro em uma string constante usando o operador de concatenação. A fim de obter tal efeito, pode-se usar a propriedade ANSI C que duas ou mais constantes de cadeia consecutivas são consideradas equivalentes a uma única constante de cadeia quando encontradas. Usando esta propriedade, pode-se escrever

#define eat( what ) puts( "I'm eating " #what " today." )eat( fruit )

qual a macro-processador vai se transformar em

puts( "I'm eating " "fruit" " today." )

, que por sua vez será interpretado pelo C analisador como uma única cadeia de caracteres constante.

O seguinte truque pode ser usado para transformar constantes numéricas em literais de cordas

#define num2str(x) str(x)#define str(x) #x#define CONST 23puts(num2str(CONST));

isto é um pouco complicado, uma vez que é expandido em 2 passos. Primeiro num2str(CONST) é substituído por str(23), que por sua vez é substituído por "23". Isto pode ser útil no seguinte exemplo:

Isto dar-lhe-á uma mensagem de depuração agradável, incluindo o ficheiro e a linha onde a mensagem foi emitida. Se a depuração não estiver definida, contudo a mensagem de depuração irá desaparecer completamente do seu código. Tenha cuidado para não usar este tipo de construção com qualquer coisa que tenha efeitos colaterais, uma vez que isso pode levar a bugs, que aparecem e desaparecem, dependendo dos parâmetros de compilação.

macrosEdit

Macros não são verificados por tipo e por isso não avaliam argumentos. Além disso, eles não obedecem escopo corretamente, mas simplesmente levam a cadeia passada para eles e substituem cada ocorrência do argumento macro no texto da macro com a cadeia real para esse parâmetro (o código é literalmente copiado para o local de onde foi chamado).

Um exemplo de como usar uma 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; }

–, o resultado de “um” deve ser “2” (b + c = 16 -> passado para ADICIONAR -> 16 / FATIAS -> resultado é “2”)

NOTA:
é, geralmente, uma prática inadequada para definir macros em cabeçalhos.

uma macro deve ser definida apenas quando não é possível alcançar o mesmo resultado com uma função ou outro mecanismo. Alguns compiladores são capazes de otimizar o código para onde as chamadas para pequenas funções são substituídas por código inline, negando qualquer vantagem de velocidade possível.O uso de digitedefs, enums e inline (em C99) é muitas vezes uma opção melhor.

uma das poucas situações em que as funções inline não funcionarão — então você é praticamente forçado a usar macros como função em vez — é inicializar constantes de tempo de compilação (inicialização estática das estruturas).Isto acontece quando os argumentos para a macro são literais que o compilador pode otimizar para outro literal.

#errodit

a directiva # erro interrompe a compilação. Quando um é encontrado o padrão especifica que o compilador deve emitir um diagnóstico contendo os tokens restantes na diretiva. Isto é usado principalmente para fins de depuração.

programadores usam “# error ” dentro de um bloco condicional, para parar imediatamente o compilador quando o “#if” ou “#ifdef” — no início do bloco — detecta um problema de tempo de compilação.Normalmente o compilador salta o bloco (e a diretiva “#erro” dentro dele) e a compilação prossegue.

 #error message

#warningEdit

muitos compiladores suportam uma directiva #warning. Quando um é encontrado, o compilador emite um diagnóstico contendo os tokens restantes na Directiva.

 #warning message

#undefEdit

The #undef directive undefines a macro. O identificador não precisa ter sido previamente definido.

#if, # Elif,#endif (condicionais)Edit

The #if command checks whether a controlling conditional expression evaluates to zero or nonzero, and excludes or includes a block of code respectively. Por exemplo:

 #if 1 /* This block will be included */ #endif #if 0 /* This block will not be included */ #endif

A expressão condicional pode conter qualquer C operador, exceto para os operadores de atribuição, o incremento e o decremento os operadores, o endereço do operador e o operador sizeof.

um operador único usado no pré-processamento e em nenhum outro lugar é o operador definido. Devolve 1 Se o nome da macro, colocado opcionalmente entre parêntesis, estiver definido de momento; 0 se não estiver.

O #endif comando termina um bloco iniciado por #if#ifdef, ou #ifndef.

o comando # elif é semelhante a#if, exceto que é usado para extrair um de uma série de blocos de código. E. g.:

 #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

A #ifdef comando é semelhante a #if, exceto que o bloco de código a seguir é selecionado se o nome da macro estiver definido. A este respeito,

#ifdef NAME

é equivalente a

#if defined NAME

A #ifndef comando é semelhante a #ifdef, exceto que o teste é invertida:

#ifndef NAME

é equivalente a

#if !defined NAME

#lineEdit

Esta diretiva de pré-processamento é utilizado para definir o nome do arquivo e o número da linha seguinte directiva para os novos valores. Isto é usado para definir o _ _ ficheiro__ e _ _ linha_ _ macros.

Deixe uma resposta

O seu endereço de email não será publicado.