Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
c:conversao_de_tipos [2023/08/01 18:10] – criada maziero | c:conversao_de_tipos [2023/08/01 20:16] (atual) – edição externa 127.0.0.1 | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Conversão de tipos ====== | ||
+ | |||
+ | {{ progc_conversao.mkv |Video desta aula}} | ||
+ | |||
+ | {{ transformation.png|https:// | ||
+ | |||
+ | Algumas conversões são efetuadas implicitamente pelo compilador, sem riscos para a integridade dos dados manipulados. Todavia, certas conversões podem levar a resultados errados ou à perda de informação e precisam ser " | ||
+ | |||
+ | ===== Conversão implícita ===== | ||
+ | |||
+ | Quando uma operação lógica/ | ||
+ | |||
+ | Na promoção automática, | ||
+ | |||
+ | A hierarquia de tipos considerada para a promoção automática é a seguinte (os tipos '' | ||
+ | |||
+ | char < short < int < long < long long < float < double < long double | ||
+ | |||
+ | <note important> | ||
+ | A regra de promoção automática é aplicada separadamente **A CADA OPERAÇÃO** da expressão lógica/ | ||
+ | </ | ||
+ | |||
+ | O código a seguir mostra alguns exemplos de promoção automática: | ||
+ | |||
+ | <code c> | ||
+ | char c = ' | ||
+ | int i = 3 ; | ||
+ | short s = 31 ; | ||
+ | float f = 31.8 ; | ||
+ | double d ; | ||
+ | |||
+ | i = c + 30 ; // o valor de c (65) é convertido de char para int | ||
+ | |||
+ | d = i * f + s ; // ao avaliar i*x, i é promovido de int a float | ||
+ | // ao avaliar float + s, s é promovido de short a float | ||
+ | </ | ||
+ | |||
+ | A conversão implícita (ou automática) é realizada para as operações aritméticas ('' | ||
+ | |||
+ | Os operadores de atribuição ('' | ||
+ | |||
+ | ===== Erros de conversão ===== | ||
+ | |||
+ | A regra de promoção automática é aplicada a cada operação da expressão lógica/ | ||
+ | |||
+ | <code c erro-conversao.c> | ||
+ | #include < | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int i = 100 ; | ||
+ | int j = 6 ; | ||
+ | float x = 6 ; | ||
+ | float y ; | ||
+ | |||
+ | y = i / j * x ; // (int / int) * float -> int * float | ||
+ | printf ("y vale %f\n", y) ; // ^^^^^^^^^ divisão inteira! | ||
+ | |||
+ | y = x * i / j ; // (float * int) / int | ||
+ | printf ("y vale %f\n", y) ; // resultado correto (vide abaixo) | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Ao avaliar primeiro a operação '' | ||
+ | |||
+ | < | ||
+ | $ ./ | ||
+ | y vale 96.000000 | ||
+ | y vale 100.000000 | ||
+ | </ | ||
+ | |||
+ | As expressões são usualmente avaliadas da esquerda para a direita, mas isso depende da precedência dos operadores, além do compilador e do nível de otimização usado. Por isso, a ordem de avaliação das operações em uma expressão envolvendo tipos distintos deve ser explicitada usando **parênteses**: | ||
+ | |||
+ | <code c> | ||
+ | y = (x * i) / j ; // (float * int) / int | ||
+ | printf ("y vale %f\n", y) ; // resultado correto sempre | ||
+ | </ | ||
+ | |||
+ | A conversão implícita na atribuição também pode provocar perda de informação. O exemplo abaixo mostra algumas dessas situações: | ||
+ | |||
+ | <code c perdas.c> | ||
+ | #include < | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | char c ; | ||
+ | int i ; | ||
+ | long l ; | ||
+ | float f ; | ||
+ | double d ; | ||
+ | |||
+ | c = ' | ||
+ | i = c ; // ok, pois int > char | ||
+ | printf ("c = %d, i = %d\n", c, i) ; | ||
+ | |||
+ | i = 34 ; | ||
+ | f = i ; // ok, pois float > int | ||
+ | printf ("i = %d, f = %f\n", i, f) ; | ||
+ | |||
+ | l = 214748364347243 ; | ||
+ | f = l ; // perda de precisão | ||
+ | printf ("l = %ld, f = %f\n", l, f) ; | ||
+ | |||
+ | l = 214748364347243 ; | ||
+ | d = l ; // ok, precisão suficiente | ||
+ | printf ("l = %ld, d = %lf\n", | ||
+ | |||
+ | f = 451.28 ; | ||
+ | i = f ; // parte fracionária é truncada | ||
+ | printf ("f = %f, i = %d\n", f, i) ; | ||
+ | |||
+ | d = 3.141592653589793264 ; | ||
+ | f = d ; // perda de precisão | ||
+ | printf ("d = %.15f, f = %.15f\n", | ||
+ | |||
+ | l = 12345677890 ; | ||
+ | i = l ; // perda dos bits mais significativos | ||
+ | printf ("l = %ld, i = %d\n", l, i) ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <note important> | ||
+ | Observe que a precisão de um '' | ||
+ | </ | ||
+ | |||
+ | ===== 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: | ||
+ | |||
+ | <code c media-erro.c> | ||
+ | #include < | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int soma, num ; | ||
+ | float media ; | ||
+ | |||
+ | soma = 10 ; | ||
+ | num = 4 ; | ||
+ | |||
+ | media = soma / num ; | ||
+ | |||
+ | printf (" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | No caso acima, a expressão '' | ||
+ | |||
+ | * adicionando um elemento neutro de tipo '' | ||
+ | * forçando a avaliação de '' | ||
+ | |||
+ | <code c media.c> | ||
+ | #include < | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int soma, num ; | ||
+ | float media ; | ||
+ | |||
+ | soma = 10 ; | ||
+ | num = 4 ; | ||
+ | |||
+ | media = soma / num ; // errado, perda de precisão | ||
+ | printf (" | ||
+ | |||
+ | media = 1.0 * soma / num ; // soma é " | ||
+ | printf (" | ||
+ | |||
+ | media = (float) soma / num ; // soma é avaliada como float (casting) | ||
+ | printf (" | ||
+ | |||
+ | media = soma / (float) num ; // num é avaliado como float (casting) | ||
+ | printf (" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | <note tip> | ||
+ | A avaliação forçada de um valor ou variável para um tipo específico usando o prefixo '' | ||
+ | </ | ||
+ | |||
+ | ===== Conversão de ponteiros ===== | ||
+ | |||
+ | Uma operação frequente em C é a conversão de tipos de ponteiros. Muitas funções importantes, | ||
+ | |||
+ | Como ponteiros para '' | ||
+ | |||
+ | O exemplo a seguir mostra como ponteiros '' | ||
+ | |||
+ | <code c qsort.c> | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #define VETSIZE 10 | ||
+ | |||
+ | int vetor[VETSIZE] ; | ||
+ | |||
+ | // compara dois inteiros apontados por " | ||
+ | int compara_int (const void* a, const void* b) | ||
+ | { | ||
+ | int *pa, *pb ; | ||
+ | |||
+ | pa = (int*) a ; // " | ||
+ | pb = (int*) b ; // idem, b | ||
+ | |||
+ | if (*pa > *pb) return | ||
+ | if (*pa < *pb) return -1 ; | ||
+ | return 0 ; | ||
+ | } | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | int i ; | ||
+ | |||
+ | // preenche o vetor de inteiros com aleatórios | ||
+ | for (i = 0; i < VETSIZE; i++) | ||
+ | vetor[i] = random() % 1000 ; | ||
+ | |||
+ | // escreve o vetor | ||
+ | for (i = 0; i < VETSIZE; i++) | ||
+ | printf ("%d ", vetor[i]) ; | ||
+ | printf (" | ||
+ | |||
+ | // ordena o vetor (man qsort) | ||
+ | // Protótipo: int (*compara_int) (const void *, const void *) | ||
+ | qsort (vetor, VETSIZE, sizeof (int), compara_int) ; | ||
+ | |||
+ | // escreve o vetor | ||
+ | for (i = 0; i < VETSIZE; i++) | ||
+ | printf ("%d ", vetor[i]) ; | ||
+ | printf (" | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Conversão de/para strings ===== | ||
+ | |||
+ | No caso específico de strings, a conversão destas para outros tipos é efetuada através de funções específicas: | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | |||
+ | // string to float, int, long, long long | ||
+ | double | ||
+ | int | ||
+ | long atol (const char *str) ; | ||
+ | long long atoll (const char *str) ; | ||
+ | |||
+ | // string to double, float, long double, com teste de erro | ||
+ | double strtod (const char *nptr, char **endptr) ; | ||
+ | float strtof (const char *nptr, char **endptr) ; | ||
+ | long | ||
+ | </ | ||
+ | |||
+ | No sentido //número → string//, a forma mais simples de converter um dado de qualquer tipo para //string// é usando a função '' | ||
+ | |||
+ | <code c float2string.c> | ||
+ | #include < | ||
+ | |||
+ | int main () | ||
+ | { | ||
+ | char buffer[256] ; | ||
+ | float x ; | ||
+ | | ||
+ | x = 32.4 / 7 ; | ||
+ | |||
+ | sprintf (buffer, " | ||
+ | |||
+ | printf (" | ||
+ | | ||
+ | return 0 ; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== Leitura complementar ===== | ||
+ | |||
+ | * [[https:// | ||