Conversão de tipo - Type conversion

Em ciência da computação , conversão de tipo , tipo carcaça , tipo de coerção , e tipo de malabarismo são diferentes maneiras de mudar uma expressão de um tipo de dados para outro. Um exemplo seria a conversão de um valor inteiro em um valor de ponto flutuante ou sua representação textual como uma string e vice-versa. As conversões de tipo podem tirar proveito de certos recursos de hierarquias de tipo ou representações de dados . Dois aspectos importantes de uma conversão de tipo são se ela ocorre implícita (automaticamente) ou explicitamente e se a representação de dados subjacente é convertida de uma representação em outra, ou uma determinada representação é meramente reinterpretada como a representação de outro tipo de dados. Em geral, os tipos de dados primitivos e compostos podem ser convertidos.

Cada linguagem de programação tem suas próprias regras sobre como os tipos podem ser convertidos. Linguagens com tipagem forte geralmente fazem pouca conversão implícita e desencorajam a reinterpretação de representações, enquanto linguagens com tipagem fraca realizam muitas conversões implícitas entre tipos de dados. Linguagem de digitação fraca geralmente permite forçar o compilador a interpretar arbitrariamente um item de dados como tendo diferentes representações - isso pode ser um erro de programação não óbvio ou um método técnico para lidar diretamente com o hardware subjacente.

Na maioria dos idiomas, a palavra coerção é usada para denotar uma conversão implícita , durante a compilação ou durante o tempo de execução . Por exemplo, em uma expressão que mistura números inteiros e números de ponto flutuante (como 5 + 0,1), o compilador converterá automaticamente a representação de inteiro em representação de ponto flutuante para que as frações não sejam perdidas. As conversões explícitas de tipo são indicadas escrevendo código adicional (por exemplo, adicionando identificadores de tipo ou chamando rotinas integradas ) ou codificando rotinas de conversão para o compilador usar quando, de outra forma, ele pararia com uma incompatibilidade de tipo.

Na maioria dos ALGOL -como linguagens, como Pascal , Modula-2 , Ada e Delphi , conversão e fundição são distintamente diferentes conceitos. Nessas linguagens, a conversão se refere à alteração implícita ou explícita de um valor de um formato de armazenamento de tipo de dados para outro, por exemplo, um inteiro de 16 bits para um inteiro de 32 bits. As necessidades de armazenamento podem mudar como resultado da conversão, incluindo uma possível perda de precisão ou truncamento. A palavra cast , por outro lado, refere-se a alterar explicitamente a interpretação do padrão de bits que representa um valor de um tipo para outro. Por exemplo, 32 bits contíguos podem ser tratados como uma matriz de 32 booleanos, uma string de 4 bytes, um número inteiro de 32 bits sem sinal ou um valor de ponto flutuante de precisão única IEEE. Como os bits armazenados nunca são alterados, o programador deve conhecer detalhes de baixo nível, como formato de representação, ordem de bytes e necessidades de alinhamento, para lançar de forma significativa.

Na família de linguagens C e ALGOL 68 , a palavra elenco normalmente se refere a uma conversão de tipo explícita (em oposição a uma conversão implícita), causando alguma ambigüidade sobre se esta é uma reinterpretação de um padrão de bits ou uma representação de dados real conversão. Mais importante é a variedade de maneiras e regras que se aplicam a que tipo de dados (ou classe) é localizado por um ponteiro e como um ponteiro pode ser ajustado pelo compilador em casos como herança de objeto (classe).

Comparação de linguagem

Linguagens semelhantes a C

Conversão de tipo implícita

A conversão implícita de tipo, também conhecida como coerção , é uma conversão automática de tipo pelo compilador . Algumas linguagens de programação permitem que os compiladores forneçam coerção; outros exigem isso.

Em uma expressão de tipo misto, os dados de um ou mais subtipos podem ser convertidos em um supertipo conforme necessário no tempo de execução para que o programa seja executado corretamente. Por exemplo, o seguinte é um código de linguagem C legal :

double  d;
long    l;
int     i;

if (d > i)   d = i;
if (i > l)   l = i;
if (d == l)  d *= 2;

Embora d , l e i pertençam a tipos de dados diferentes, eles serão convertidos automaticamente em tipos de dados iguais cada vez que uma comparação ou atribuição for executada. Esse comportamento deve ser usado com cuidado, pois podem surgir consequências indesejadas . Os dados podem ser perdidos ao converter representações de ponto flutuante em inteiro, pois os componentes fracionários dos valores de ponto flutuante serão truncados (arredondados para zero). Por outro lado, a precisão pode ser perdida ao converter representações de inteiro em ponto flutuante, uma vez que um tipo de ponto flutuante pode ser incapaz de representar exatamente um tipo inteiro. Por exemplo, floatpode ser um tipo de precisão única IEEE 754 , que não pode representar o inteiro 16777217 exatamente, enquanto um tipo inteiro de 32 bits pode. Isso pode levar a um comportamento não intuitivo, conforme demonstrado pelo seguinte código:

#include <stdio.h>

int main(void)
{
    int i_value   = 16777217;
    float f_value = 16777216.0;
    printf("The integer is: %d\n", i_value);
    printf("The float is:   %f\n", f_value);
    printf("Their equality: %d\n", i_value == f_value);
}

Em compiladores que implementam floats como precisão única IEEE e ints como pelo menos 32 bits, este código fornecerá esta impressão peculiar:

The integer is: 16777217
The float is: 16777216.000000
Their equality: 1

Observe que 1 representa a igualdade na última linha acima. Esse comportamento estranho é causado por uma conversão implícita de i_valuepara float quando comparado com f_value. A conversão causa perda de precisão, o que torna os valores iguais antes da comparação.

Pontos importantes:

  1. floatpara intcausar truncamento , ou seja, remoção da parte fracionária.
  2. doublepara floatcausa o arredondamento do dígito.
  3. longpara intcausar o descarte de bits de ordem superior em excesso.
Promoção de tipo

Um caso especial de conversão implícita de tipo é a promoção de tipo, onde o compilador expande automaticamente a representação binária de objetos de tipo inteiro ou de ponto flutuante. As promoções são comumente usadas com tipos menores do que o tipo nativo da unidade lógica aritmética (ALU) da plataforma de destino , antes das operações aritméticas e lógicas, para tornar essas operações possíveis ou mais eficientes se a ALU puder trabalhar com mais de um tipo. C e C ++ realizam tal promoção para objetos dos tipos booleano, caractere, caractere largo, enumeração e inteiro curto que são promovidos para int e para objetos do tipo float, que são promovidos para double. Ao contrário de algumas outras conversões de tipo, as promoções nunca perdem a precisão ou modificam o valor armazenado no objeto.

Em Java :

int x = 3;
double y = 3.5;
System.out.println(x + y); // The output will be 6.5

Conversão de tipo explícito

A conversão explícita de tipo é uma conversão de tipo explicitamente definida dentro de um programa (em vez de ser feita por um compilador para a conversão implícita de tipo). É definido pelo usuário no programa.

double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; // result == 9
// if implicit conversion would be used (as with "result = da + db + dc"), result would be equal to 10

Existem vários tipos de conversão explícita.

verificado
Antes de a conversão ser realizada, uma verificação de tempo de execução é feita para ver se o tipo de destino pode conter o valor de origem. Caso contrário, uma condição de erro será levantada.
não verificado
Nenhuma verificação é executada. Se o tipo de destino não pode conter o valor de origem, o resultado é indefinido.
Padrão de bits
A representação de bits brutos da origem é copiada literalmente e é reinterpretada de acordo com o tipo de destino. Isso também pode ser feito por meio de aliasing .

Em linguagens de programação orientadas a objetos, os objetos também podem ser  convertidos em downcast : uma referência de uma classe base é convertida em uma de suas classes derivadas.

C # e C ++

Em C # , a conversão de tipo pode ser feita de uma maneira segura ou insegura (ou seja, semelhante ao C), a anterior chamada de conversão de tipo verificado .

Animal animal = new Cat();

Bulldog b = (Bulldog) animal;  // if (animal is Bulldog), stat.type(animal) is Bulldog, else an exception
b = animal as Bulldog;         // if (animal is Bulldog), b = (Bulldog) animal, else b = null

animal = null;
b = animal as Bulldog;         // b == null

Em C ++, um efeito semelhante pode ser obtido usando a sintaxe de conversão no estilo C ++ .

Animal* animal = new Cat;

Bulldog* b = static_cast<Bulldog*>(animal); // compiles only if either Animal or Bulldog is derived from the other (or same)
b = dynamic_cast<Bulldog*>(animal);         // if (animal is Bulldog), b = (Bulldog*) animal, else b = nullptr

Bulldog& br = static_cast<Bulldog&>(*animal); // same as above, but an exception will be thrown if a nullptr was to be returned
                                              // this is not seen in code where exception handling is avoided
animal = nullptr;
b = dynamic_cast<Bulldog*>(animal);         // b == nullptr

delete animal; // always free resources

Eiffel

Em Eiffel, a noção de conversão de tipo é integrada às regras do sistema de tipo. A regra de atribuição diz que uma atribuição, como:

x := y

é válido se e somente se o tipo de sua expressão de origem, yneste caso, for compatível com o tipo de sua entidade de destino, xneste caso. Nesta regra, compatível com significa que o tipo da expressão de origem está em conformidade com ou se converte ao do destino. A conformidade de tipos é definida pelas regras familiares de polimorfismo na programação orientada a objetos . Por exemplo, na atribuição acima, o tipo de yestá em conformidade com o tipo de xse a classe na qual yse baseia é descendente daquela na qual xse baseia.

Definição de conversão de tipo em Eiffel

As ações de conversão de tipo em Eiffel, especificamente converte para e converte de, são definidas como:

Um tipo baseado em uma classe CU converte em um tipo T com base em uma classe CT (e T converte de U) se qualquer um

CT tem um procedimento de conversão usando U como um tipo de conversão, ou
CU tem uma consulta de conversão listando T como um tipo de conversão

Exemplo

Eiffel é uma linguagem totalmente compatível com o Microsoft .NET Framework . Antes do desenvolvimento do .NET, Eiffel já tinha extensas bibliotecas de classes. Usar as bibliotecas de tipos .NET, particularmente com tipos comumente usados, como strings, apresenta um problema de conversão. O software Eiffel existente usa as classes de string (como STRING_8) das bibliotecas Eiffel, mas o software Eiffel escrito para .NET deve usar a classe de string .NET ( System.String) em muitos casos, por exemplo, ao chamar métodos .NET que esperam itens do .NET tipo a ser passado como argumentos. Portanto, a conversão desses tipos para frente e para trás precisa ser o mais uniforme possível.

    my_string: STRING_8                 -- Native Eiffel string
    my_system_string: SYSTEM_STRING     -- Native .NET string

        ...

            my_string := my_system_string

No código acima, duas strings são declaradas, uma de cada tipo diferente ( SYSTEM_STRINGé o alias compatível com Eiffel para System.String). Porque System.Stringnão está em conformidade com STRING_8, então a atribuição acima é válida somente se System.Stringconverte para STRING_8.

A classe Eiffel STRING_8possui um procedimento de conversão make_from_cilpara objetos do tipo System.String. Os procedimentos de conversão também são sempre designados como procedimentos de criação (semelhantes aos construtores). O que se segue é um trecho da STRING_8aula:

    class STRING_8
        ...
    create
        make_from_cil
        ...
    convert
        make_from_cil ({SYSTEM_STRING})
        ...

A presença do procedimento de conversão faz com que a cessão:

            my_string := my_system_string

semanticamente equivalente a:

            create my_string.make_from_cil (my_system_string)

no qual my_stringé construído como um novo objeto do tipo STRING_8com conteúdo equivalente ao de my_system_string.

Para lidar com uma atribuição com origem original e destino invertidos:

            my_system_string := my_string

a classe STRING_8também contém uma consulta de conversão to_cilque produzirá um a System.Stringpartir de uma instância de STRING_8.

    class STRING_8
        ...
    create
        make_from_cil
        ...
    convert
        make_from_cil ({SYSTEM_STRING})
        to_cil: {SYSTEM_STRING}
        ...

A atribuição:

            my_system_string := my_string

então, torna-se equivalente a:

            my_system_string := my_string.to_cil

Em Eiffel, a configuração para conversão de tipo está incluída no código da classe, mas parece acontecer tão automaticamente quanto a conversão de tipo explícita no código do cliente. Inclui não apenas atribuições, mas também outros tipos de anexos, como substituição de argumento (parâmetro).

Ferrugem

Rust não fornece conversão de tipo implícita (coerção) entre tipos primitivos. Porém, a conversão explícita de tipo (conversão) pode ser realizada usando a aspalavra - chave.

println!("1000 as a u16 is: {}", 1000 as u16);

Problemas de segurança

Em hacking , typecasting é o uso indevido da conversão de tipo para alterar temporariamente o tipo de dados de uma variável de como foi originalmente definido. Isso oferece oportunidades para hackers, pois na conversão de tipo após uma variável ser "typecast" para se tornar um tipo de dados diferente, o compilador tratará essa variável hackeada como o novo tipo de dados para aquela operação específica.

Veja também

Referências

links externos