sábado, 4 de fevereiro de 2012

C: Dualidade char/int

Uma das definições para Byte é: "Byte a quantidade mínima de bits necessários para armazenar um caractere.". Memória, capacidade de armazenamento, tamanho de variáveis etc, são medidos em bytes, ou seus múltiplos (KB, MB etc).

Normalmente o Byte tem 8 bits, mas já li que houve uma exceção (um processador com o Byte de 9 bits).

O tipo char no C é este inteiro de um Byte, que pode ser usado para armazenar um número inteiro que caiba em um Byte, ou um caractere, e não é um tipo restritivo como outras linguagens de alto nível.

Então, algo como 'a' é uma constante numérica, tal como o número 97 (número na tabela ASCII para o letra a minúsculo).

Para converter uma letra minúscula em maiúscula basta subtrair a diferença entre as letras maiúsculas e minúsculas, como mostrado abaixo:
        letra = letra - 'a' + 'A' ;

Ou melhor, da forma mais compacta:

        letra -= 'a' + 'A' ;

Com a variável letra sendo do tipo  char. Aliás, até pode ser int, por que a expressão é inteira, mas outros usos podem vir a sofrer restrições, conforme o algoritmo.

Um outro exemplo é a função que transforma de string (isto será explicado oportunamente, mas pode ler sobre isto em livros de C) para número.

int atoi( char *str )
{
        int     valor   = 0     ;

        for( ; *str ; str++ )
                valor = valor*10 + *str - '0' ;

        return valor;
}

Esta é uma forma compacta para esta função, que pode não ser entendida por quem está no início do aprendizado, mas vou explicar. Para cada caractere da string, multiplique o valor anterior da variável valor por 10, e some o caractere ASCII e subtraia o ASCII do caractere zero. Quando acabar retorne o resultado das contas.

O tipo do *str é char e contém um caractere que representa o número. Se o caractere '2', que estiver no *str, for subtraído pelo caractere '0', teremos o valor inteiro 2. É assim que funciona. Em outras linguagem seria necessária a conversão de tipo, mas no C, com a dualidade char/int isto não é necessário.

Outro efeito interessante é se, por exemplo, existe a necessidade de armazenar 10 milhões de números inteiros de 0 a 100 em um array na memória. Vai ciar um array de inteiros para isto? Irá gastar 20 ou 40 MB, quando poderia usar somente 10 MB se este array for de char. Uma tipagem forte não permitiria esta solução tão facilmente.

Outro exemplo interessante é o abaixo:

{
        char    i               ,
                letras[ 26 ]    ;

        for( i = 0 ; i < 26 ; i++ )
                letras[ i ] = i + 'a' ;
}

Sim, o tipo char foi usado como variável de controle (em muitos casos, o código pode ficar mais eficiente com o tipo int) e na atribuição.

Parece misturado? Ainda não viu tudo:

{
        int     i       ;
        char    letras[ 26 ]    ;
               
        for( i = 'a' ; i <= 'z' ; i++ )
                letras[ i - 'a' ] = i  ;
}

Que tal agora? Deu para sentir que o char é um inteiro que cabe um caractere, e não exatamente um caractere de uso restrito? (Tem métodos de fazer o algoritmo acima ficar melhor, mas não vem ao caso.)

Outro exemplo interessante é a função getchar() e correlatas. Elas são funções para ler caracteres, mas o seu valor de retorno não é do tipo char, e sim, int. Qual é a utilidade disto? Na situação normal elas retornam valores entre 0 e 255, conforme o que lê, mas quando chega ao final do arquivo ela retorna o valor ditado pela contante EOF, que é -1, que não pertence a faixa dos caracteres, assinalando assim um erro.

Como pôde ver acima, esta dualidade char/int do C aumenta os poderes da linguagem, aproxima do modo que o processador realmente enxerga as coisas, e também cria um bando de flexibilidades e possibilidades.

Nenhum comentário:

Postar um comentário