sexta-feira, 24 de fevereiro de 2012

C: Ser ou não ser - Boolean

No C não existe o tipo boolean, tal como existe em outras linguagens, mas existem operações lógicas. As operações lógicas são operações inteiras de baixo nível de precedência.

Então podemos fazer uma operação lógica e atribuir a uma variável inteira. Veja o exemplo abaixo:

static  int     valido( a,b,c )
int     a,b,c   ;
{
        return ( a < b ) && ( b < c ) ;
}

int     main()
{
        int     x,y,z,l,m,n,b   ;


        /* ... */

        if( valido( x,y,z ) )
        {
                /* ... */
        }

        if( b = valido( l,m,n ) )
        {
                /* ... */
        }

        if( b && ( l > z ) )
        {
                /* ... */
        }
}

No exemplo acima uma função retorna o resultado de uma expressão lógica, e no segundo if o valor retornado pela função também é atribuído à variável b, que é usada na expressão do terceiro if.

Mas que valores inteiros a função valido() pode retornar? Vamos testar:

#include        <stdio.h>

static  int     valido( a,b,c )
int     a,b,c   ;
{
        return ( a < b ) && ( b < c ) ;
}

int     main()
{
        printf( "%d\n",valido( 1,2,3 ) );
        printf( "%d\n",valido( 3,2,1 ) );
}

E o resultado é (e que rufem os tambores)...

1
0

Quando verdadeira, a expressão retorna 1, quando falsa, retorna 0.

Na realidade, o compilador só gera código que resulte num inteiro quando é pedido, pois isto é custoso, e para determinar se um resultado é verdadeiro ou não, uma instrução de comparação é executada pelo processador, mudando, conforme o resultado desta comparação, o estado de um conjunto de flags. Intruções de jumps condicionais, que dependem destas flags, são usadas para fazer os desvios na execução do código. (De novo, para um melhor entendimento, é necessário saber Assembler.) Todos os compiladores fazem isto, em todas as linguagens, não somente os compiladores C.

Não importando como o compilador vai gerar o código, ao nível do programador a expressão age da mesma forma, como uma expressão do tipo inteiro. E isto serve para criar uns atalhos.

Se resultado de uma expressão lógica é 0 ou 1, mas ela é uma operação inteira, onde outros números são aceitos, o que acontece com os valores diferente de 0 e 1? A solução mais simples é só definir o falso como 0, que é bem fácil de testar (O PDP 11/70 tinha uma instrução para testar sem fazer comparação, mudando as flags de acordo com o valor testado, e outros processadores podem fazer operações de bits, como or ou and, que alteram as flags de acordo.), e o resto como sendo verdadeiro. Isto tem implicações úteis.

        int     i       ;

        /* if( i != 0 ) */
        if( i )
        {
                /* ... */
        }

        /* if( i == 0 ) */
        if( ! i )
        {
                /* ... */
        }

        for( i = 10 ; i ; i-- )
        {
                /* ... */
        }

Testes podem ser simplificados. (O truque do for acima merece uma explicação melhor, pois é uma otimização de código, porém é assunto para um outro artigo. Mas você já pode começar a deduzir.)

Uma otimização de uso de memória pode ser feita usando a Dualidade char/int. Quando necessitar de um array para guardar resultados de variáveis lógicas, pode usar o tipo char, fazendo um array de char, e gastando menos memória.

Muitos programadores C criam o boolean, só por questões de legibilidade e elegância, usando uma das diversas formas abaixo, ou alguma outra não mostrada.

#define boolean int

#define boolean char

typedef char boolean ;

E criam true e false usando uma das diversas formas existentes, mas gosto da forma abaixo:

#define FALSE (0)
#define TRUE  (! FALSE )

De novo, existem muitas formas de fazer isto.

Nenhum comentário:

Postar um comentário