User Tools

Site Tools


prog2:conversao_de_tipos

Conversão de tipos

Muitas vezes, uma expressão lógica ou aritmética envolve variáveis e constantes de tipos distintos, como char, int, float e double. Algumas conversões são efetuadas implicitamente pelo compilador, sem riscos para a integridade dos dados manipulados. Todavia, algumas conversões podem levar à perda de informação e precisam ser “forçadas” pelo programador, através de conversões explícitas.

Conversão implícita

Quando uma expressão envolve operandos de diversos tipos, o compilador primeiro os converte para um único tipo, antes de avaliar a expressão. Nos caso de tipos numéricos, essa conversão é definida pela regra de promoção automática, segundo a qual os tipos de tamanho menor (com menos bytes) são automaticamente convertidos (“promovidos”) para tipos de maior tamanho (com mais bytes).

A hierarquia de tipos considerada para a promoção automática é a seguinte (os tipos unsigned estão no mesmo nível de hierarquia que seus equivalentes signed.):

char < short < int < long < long long < float < double < long double

Por exemplo, na expressão a seguir, as variáveis à direita da atribuição (sinal “=”) são convertidas para um tipo único, antes da expressão ser avaliada:

char   c = 'A' ;
int    i = 3, j = 54;
short  k = 31 ;
float  x = 31.8 ;
double y ;
 
j = c + 30 ;	//  o valor de c (65) é convertido para int
 
y = i * x + k ;	// os valores de i e k são convertidos para float

A conversão implícita (ou automática) é realizada para as expressões aritméticas (+ - * / %), relacionais (< <= > >= == !=), com bits (& | ^) e para o operador condicional (? :).

Os operadores de atribuição (=, =+, …) também recebem uma conversão implícita de tipo, para compatibilizar o valor atribuído (lado direito) à variável que está sendo atribuída (lado esquerdo). Em alguns casos, a conversão implícita na atribuição pode haver perda de informação. Exemplos:

char c = 'A' ;
int i, j = 34 ;
long long k = 12345677890 ;
float x, y = 451.28 ;
double pi = 3.141592653589793264 ;
 
i = c ;		// ok, pois int > char
x = i ;		// ok, pois float > int
i = y ;		// problema, parte fracionária será truncada
x = pi ;	// problema, perda de precisão
i = k ;		// problema, perderá os bits mais significativos

Conversão explícita

Em alguns casos, é necessário forçar a conversão de tipos de dados, para que uma expressão seja avaliada da forma correta.

Por exemplo:

int soma, num ;
float media ;
 
soma = 100 ;
num  = 40 ;
 
media = soma / num ;		// media = 2.0 (por que?)

No caso acima, a expressão soma / num será avaliada como int / int, resultando em uma divisão inteira e consequente perda de precisão. Para gerar o resultado correto, a expressão deve ser avaliada como float. Isso pode ser obtido de duas formas:

  • adicionando um elemento neutro de tipo float à expressão;
  • forçando a avaliação de soma ou num como float.
int soma, num ;
float media ;
 
soma = 100 ;
num  = 40 ;
 
media = soma / num ;		// errado, perda de precisão
media = 1.0 * soma / num ;	// soma é "promovida" a float
media = (float) soma / num ;	// soma é avaliada como float (casting)
media = soma / (float) num ;	// num é avaliado como float (casting)

A avaliação forçada de um valor ou variável para um tipo específico usando o prefixo (type), como no exemplo acima, é chamada type casting. Essa operação é muito usada, sobretudo na avaliação de ponteiros.

Conversão de/para strings

No caso específico de strings, a conversão destas para outros tipos pode ser efetuada através de funções específicas:

#include <stdlib.h>
 
double atof (const char *str);		// string to float (double)
 
int    atoi (const char *str);		// string to integer
 
long   atol (const char *str);		// string to long
 
long long atoll (const char *str);	// string to long long 

No outro sentido, a forma mais simples de converter um dado de qualquer tipo para string é usando a função sprintf, que formata e “imprime” o dado em uma string, de forma similar ao que a função printf realiza na saída padrão:

conversion.c
#include <stdio.h>
 
int main ()
{
  char buffer[256] ;
  float x ;
 
  x = 32.4 / 7 ;
 
  sprintf (buffer, "%5.4f", x) ; // "imprime" x na string buffer
 
  printf ("%s\n", buffer) ;
 
  return 0 ;
}

Conversão de ponteiros

Uma operação frequente em C é a conversão de tipos de ponteiros. Muitas funções importantes, como qsort e bsearch, usam ponteiros genéricos void* como parâmetros de entrada, para poder receber dados de diversos tipos.

Como ponteiros para void não apontam para nenhum tipo válido de dado, eles não podem ser desreferenciados (ou seja, não é possível acessar diretamente os dados que eles apontam). Por isso, ponteiros para void precisam ser convertidos em ponteiros para algum tipo válido antes de serem desreferenciados.

O exemplo a seguir mostra como ponteiros void* são convertidos em int*, dentro da função compara_int(a,b):

qsort.c
#include <stdio.h>
#include <stdlib.h>
 
int vetor[1000] ;
int vsize ;
 
// compara dois inteiros apontados por "a" e "b"
int compara_int (const void* a, const void* b)
{
  int *pa, *pb ;
 
  pa = (int*) a ;  // "vê" a como int*
  pb = (int*) b ;  // idem, b
 
  if (*pa > *pb) return  1 ;
  if (*pa < *pb) return -1 ;
  return 0 ;
}
 
int main ()
{
  int i ;
 
  // preenche o vetor de inteiros com aleatórios
  vsize = 1000 ;
  for (i = 0; i < vsize; i++)
    vetor[i] = random() % 1000 ;
 
  // ordena o vetor (man qsort)
  qsort (vetor, vsize, sizeof (int), compara_int) ;
 
  // escreve o vetor
  for (i = 0; i < vsize; i++)
    printf ("%d ", vetor[i]) ;
  printf ("\n") ;
}

Leitura complementar: Type Conversions, C in a Nutshell.

prog2/conversao_de_tipos.txt · Last modified: 2019/01/31 17:27 (external edit)