A conversão de tipos em C é o processo de transformar um valor de um tipo de dado para outro. Isso pode ocorrer automaticamente (conversão implícita) ou ser forçada pelo programador (casting explícito). Compreender essas conversões é fundamental para evitar perda de dados, comportamentos inesperados e bugs sutis.

Em C, os tipos têm hierarquias e tamanhos diferentes. A conversão pode envolver tipos inteiros, ponto flutuante e ponteiros. Nesta aula, exploraremos os mecanismos de conversão, a promoção de inteiros e as armadilhas mais comuns, com exemplos práticos.

Conversão implícita

A conversão implícita (ou automática) ocorre quando o compilador converte um tipo para outro sem intervenção do programador. Isso acontece em expressões que misturam tipos diferentes, em atribuições e na passagem de argumentos para funções.

Por exemplo, ao atribuir um valor inteiro a uma variável do tipo float, o inteiro é convertido automaticamente para float:

int a = 10;
float b = a;  // conversão implícita de int para float
printf("%f\n", b);  // imprime 10.000000

Em expressões aritméticas com operandos de tipos diferentes, o compilador realiza a conversão para um tipo comum, seguindo regras de hierarquia (por exemplo, int para float, float para double). Exemplo:

int x = 5;
double y = 2.5;
double resultado = x + y;  // x é convertido para double
printf("%f\n", resultado);  // 7.500000

Casting explícito

O casting explícito permite que o programador force uma conversão de tipo, usando a sintaxe (tipo) expressão. Isso é útil quando se deseja evitar perda de dados ou quando a conversão implícita não é suficiente.

Por exemplo, para dividir dois inteiros e obter um resultado fracionário, é necessário converter pelo menos um operando para ponto flutuante:

int a = 7, b = 3;
float divisao = (float) a / b;  // casting explícito de a para float
printf("%f\n", divisao);  // 2.333333

Sem o cast, a divisão seria inteira, resultando em 2. O casting explícito também é usado para converter ponteiros, mas deve ser feito com cuidado.

Promoção

Promoção de inteiros é uma conversão implícita que ocorre em expressões aritméticas e lógicas. Tipos como char e short são promovidos para int (ou unsigned int) antes da operação. Isso garante que as operações sejam realizadas com a precisão mínima do tipo int.

Exemplo:

char c1 = 'A', c2 = 'B';
int soma = c1 + c2;  // c1 e c2 são promovidos a int
printf("%d\n", soma);  // 131 (65 + 66)

A promoção também ocorre em expressões com operadores relacionais e lógicos. É importante notar que a promoção pode causar comportamentos inesperados se o tipo promovido for unsigned, especialmente em comparações.

Armadilhas

A conversão de tipos em C apresenta várias armadilhas que podem levar a erros. Uma delas é a perda de dados ao converter de um tipo maior para um menor. Por exemplo, converter um long para int pode truncar o valor se ele exceder o intervalo do int.

Outra armadilha comum é a conversão de ponto flutuante para inteiro, que descarta a parte fracionária (truncamento). Exemplo:

double pi = 3.14159;
int parteInteira = (int) pi;  // parteInteira = 3 (truncado)
printf("%d\n", parteInteira);

Comparações entre tipos signed e unsigned também são problemáticas. Quando um int negativo é comparado com um unsigned int, o int é convertido para unsigned, resultando em um valor grande positivo, o que pode levar a resultados inesperados.

int a = -1;
unsigned int b = 1;
if (a < b) {
    printf("-1 é menor que 1\n");
} else {
    printf("-1 NÃO é menor que 1\n");  // Este é impresso!
}

Nesse caso, a expressão a < b converte a para unsigned, tornando-o um número muito grande (UINT_MAX), então a comparação falha.

Boas práticas

Para evitar armadilhas, sempre use casting explícito quando a conversão não for óbvia ou quando houver risco de perda de dados. Prefira tipos consistentes em expressões e evite misturar signed e unsigned sem necessidade. Ative os avisos do compilador (flags como -Wall -Wextra) para detectar conversões suspeitas.

Referências

Exercícios

  1. Escreva um programa que declare um int com valor 257 e um char. Atribua o int ao char e imprima ambos. Explique o resultado.
  2. ✓ Resposta: O programa pode ser:
    #include <stdio.h>
    int main() {
        int a = 257;
        char c = a;
        printf("int: %d, char: %d\n", a, c);
        return 0;
    }
    O char tem apenas 8 bits, então armazena apenas os 8 bits menos significativos de 257 (que é 00000001 00000001 em binário). O valor armazenado é 1 (truncamento).
  3. Dado o código: double d = 3.9; int i = d; printf("%d\n", i); Qual será a saída? Explique.
  4. ✓ Resposta: A saída será 3. A conversão de double para int trunca a parte fracionária, descartando .9.
  5. Escreva um programa que calcule a média de dois inteiros usando casting explícito para garantir resultado fracionário.
  6. ✓ Resposta:
    #include <stdio.h>
    int main() {
        int a = 5, b = 2;
        double media = (double) (a + b) / 2;
        printf("Média: %f\n", media);  // 3.500000
        return 0;
    }
  7. O que acontece quando se compara um int negativo com um unsigned int? Dê um exemplo.
  8. ✓ Resposta: O int negativo é convertido para unsigned, tornando-se um número grande. Exemplo:
    int a = -1;
    unsigned int b = 1;
    if (a < b) {
        printf("menor\n");
    } else {
        printf("maior\n");  // imprime "maior"
    }
  9. Explique a diferença entre promoção de inteiros e conversão implícita em atribuições.
  10. ✓ Resposta: Promoção de inteiros é uma conversão implícita que ocorre em expressões aritméticas/lógicas, elevando tipos menores que int para int. Conversão implícita em atribuição ocorre quando o valor do lado direito é convertido para o tipo da variável à esquerda, podendo envolver tipos diferentes (ex: int para float).