Curso de C

Gabarito de Lista de Exercícios

Aula 7: Diretivas de Compilação

Clique aqui para acessar a Lista 7

 
Exercício 1:
Verifique o programa abaixo e tente identificar problemas que irão ocorrer em tempo de execução. (Você pode usar um debugger, ou colocar printf's para tentar 'ver' os valores das variáveis).

#define max(A,B) ((A>B) ? (A):(B))
#define min(A,B) ((A<B) ? (A):(B))
#define sqr(x) x*x
void main()
{
int a = 10 ,b = 50, minimo, maximo, quad;
int z = 5;
minimo = min(a,b);
maximo = max(a++,b++);
quad = sqr(z+1);
}

Verifique o que acontece também, se mudarmos a linha de declarações do programa
int a = 10 ,b = 50, minimo, maximo, quad;

por
float a = 10 ,b = 50, minimo, maximo, quad;

Solução:
- a primeira linha, onde se calcula o mínimo de a e b (min(a,b)) é tranquilo, tudo funciona normalmente. A linha
minimo = min(a,b);

é substituída por
minimo = ((a<b) ? (a):(b));

que irá retornar o mínimo entre a e b, corretamente.

- a segunda linha,
maximo = max(a++,b++);

será substituída por
maximo = ((a++>b++) ? (a++):(b++));

Em virtude disto, em tempo de execução, o programa vai incrementar as duas variaveis na hora do teste, o que pode ser indesejado. Mas o pior de tudo é que
o maior valor será incrementado duas vezes. Veja bem: se a = 10 e b = 50, quando o programa executa o teste (a++>b++)? ele incrementa a e b. Quando ele retorna o valor de b, ele atribui 51 a maximo, mas incrementa em seguida b mais uma vez (lembre da expressão: ((a++>b++) ? (a++):(b++)).
No final da linha, b=52. Isto é indesejado.

- a terceira linha:
quad = sqr(z+1);

será substituída por
quad = z+1*z+1;

em tempo de compilação, segundo a definição da macro (vide o define). Para z=5, teremos
quad = 5+1*5+1;    /* = 11  &  != 36 !!! */

Nota-se claramente que o erro é discrepante. Para resolver este problema e preciso redefinir a macro, usando parênteses, como segue:
#define quad(x)  (x)*(x)

- Ao se trocar os tipo da variável, o resultado é muito interessante: As três macros continuam funcionando perfeitamente! Se tivéssemos uma função para realizar cada uma das operações (min, max e sqr), seriam definidos tipos de retorno para cada função. Assim, se quiséssemos fazer as mesmas operações para diferentes tipos de dados (int, float, double, char), deveríamos escrever uma função para cada tipo, ou uma função com um tipo mais geral (tipo float), e pagar o preço de conversão de tipo a cada chamada. Com o uso de macros, isto se torna desnecessário.

Comentários:
É bem verdade que não se pode fazer tudo com macros. Em muitas vezes, inclusive, seu uso pode até ser meio perigoso, e deve-se tomar redrobado cuidado. Mas em casos simples como os apresentados aqui, as macros podem ser uma boa alternativa para resolver problemas menos complexos, sem excessiva geração de códigos.
 

Exercício 2:
O que faz a macro a seguir?

# ifdef PRINT
# define WRITE(X) printf X
# else
# define WRITE(X)
# endif

Como ela poderia ser utilizada?

Solução:
- Tudo depende de a expressão PRINT ter sido ou não definida anteriormente. Se PRINT foi definido, a expressão WRITE(X) vai ser definida como sendo
printf X. Se PRINT não foi definida, a expressão WRITE(X) vai ser definida como nada (definição vazia), e todas as vezes que aparecer no programa, será substituída por nada.
Isto pode ser útil se você quer rodar um programa, numa primeira instância, mostrando os valores das variáveis em vários pontos, com printf's (uma espécie de
debugger, na unha..). Você escreve os WRITE(x) e define o PRINT. Compila e roda, vendo todos os resultados. Depois, para rodar o programa sem o debugger, você simplesmente comenta a linha onde PRINT é definido. Daí, o seu programa não apresenta mais resultados na tela.
 

  Sumário

Dúvidas? Dê uma olhadinha em nosso FAQ

Perguntas para a lista do Curso de C
Curso de C do CPDEE/UFMG - 1996-1998