Conversões padrão C ++

Conversões padrão C ++
Existem dois tipos de entidade em C ++, os tipos fundamentais e os tipos de compostos. Os tipos fundamentais são os tipos escalares. Os tipos de compostos são o restante dos tipos de entidade. A conversão pode ocorrer de um tipo de entidade para outro tipo apropriado. Considere o seguinte programa: #include
#incluir
usando namespace std;
int main ()

int rt1 = sqrt (5);
int rt2 = sqrt (8);
cout<retornar 0;

A saída é 2, 2, o que significa que o programa retornou a raiz quadrada de 5 como 2 e a raiz quadrada de 8 também como 2. Então, as duas primeiras declarações no principal() A função atingiu as respostas da raiz quadrada de 5 e a raiz quadrada de 8. Este artigo não discute o piso ou o teto em C++. Em vez disso, este artigo discute a conversão de um tipo C ++ em outro tipo C ++ apropriado; indicando qualquer aproximação no valor feita, perda de precisão ou restrição adicionada ou removida. O conhecimento básico do C ++ é um pré -requisito para entender este artigo.

Conteúdo do artigo

  • Conversões integrais
  • Conversões de ponto flutuante
  • Conversões de integral flutuante
  • Classificação de conversão inteira
  • Promoções integrais
  • Conversões aritméticas usuais
  • Promoção de ponto flutuante
  • Conversões de ponteiro
  • Função para conversões de ponteiro
  • Conversões booleanas
  • Lvalue, prvalue e xvalue
  • Xvalue
  • Conversões de LValue-para-avaliação
  • Conversões de matriz a ponte
  • Conversões de função a ponto
  • Conversões de materialização temporária
  • Conversões de qualificação
  • Conclusão

Conversões integrais

Conversões integrais são conversões inteiras. Inteiros não assinados incluem "char não assinado", "Int curto não assinado", "Int não assinado", "Int Int Long não assinado" e "Long Int Long Long Int não assinado."Os números inteiros assinados correspondentes incluem" Signed Char "," Short Int "," Int "," Long Int "e" Long Long Int.”Cada tipo int deve ser mantido em tantos bytes quanto seu antecessor. Para a maioria dos sistemas, um tipo de entidade pode ser convertido em um tipo correspondente sem nenhum problema. O problema ocorre ao converter de um tipo de alcance maior para um tipo de alcance menor ou ao converter um número assinado em um número não assinado correspondente.

Cada compilador tem um valor máximo que pode levar para o curto INT. Se um número maior que o máximo, destinado a um INT, for atribuído ao curto INT, o compilador seguirá algum algoritmo e devolverá um número dentro do intervalo do curto INT. Se o programador tiver sorte, o compilador avisará os problemas ao usar conversão inadequada. A mesma explicação se aplica às conversões de outros tipos int.

O usuário deve consultar a documentação do compilador para determinar os valores limitantes para cada tipo de entidade.

Se um número INT curto assinado negativo for convertido em um número curto INT não assinado, o compilador seguirá algum algoritmo e retornará um número positivo dentro do intervalo do curto Int não assinado INT. Este tipo de conversão deve ser evitado. A mesma explicação se aplica às conversões de outros tipos int.

Qualquer número inteiro, exceto 0, pode ser convertido em verdadeiro booleano. 0 é convertido em booleano falso. O código a seguir ilustra o seguinte:

int a = -27647;
flutuar B = 2.5;
int c = 0;
bool a1 = a;
bool b1 = b;
bool c1 = c;
cout<cout<cout<A saída é:

1
1
0

1 significa verdadeiro e 0 significa falso na saída

Conversões de ponto flutuante

Os tipos de ponto flutuante incluem "Float", "Double" e "Long Double.Os tipos de ponto flutuante não são agrupados em assinados e não assinados, como números inteiros. Cada tipo pode ter um número assinado ou não assinado. Um tipo de ponto flutuante deve ter pelo menos a mesma precisão que seu antecessor. Ou seja, o “duplo longo” deve ter uma precisão igual ou maior ao “duplo” e “duplo” deve ter uma precisão igual ou maior para “flutuar.”

Lembre-se de que o alcance de um tipo de ponto flutuante não é contínuo; Em vez disso, está em pequenos passos. Quanto maior a precisão do tipo, menor as etapas e maior o número de bytes para armazenar o número. Portanto, quando um número de ponto flutuante é convertido de um tipo de precisão mais baixa em um tipo de precisão mais alta, o programador deve aceitar um aumento falso na precisão e um possível aumento no número de bytes para armazenamento de números. Quando um número de ponto flutuante é convertido de um tipo de precisão mais alta em um tipo de precisão mais baixa, o programador deve aceitar uma perda de precisão. Se o número de bytes para armazenamento de números for reduzido, o compilador seguirá algum algoritmo e retornará um número como substituto (que provavelmente não é o que o programador deseja). Além disso, lembre-se de problemas fora do alcance.

Conversões de integral flutuante

Um número de ponto flutuante é convertido em um número inteiro truncando a parte fracionária. O código a seguir ilustra o seguinte:

Float f = 56.953;
int i = f;
cout<A saída é 56. Os intervalos para o flutuador e o número inteiro devem ser compatíveis.

Quando um número inteiro é convertido em flutuação, o valor exibido como flutuação é o mesmo que foi digitado como um número inteiro. No entanto, o equivalente a flutuação pode ser o valor exato ou ter uma leve diferença fracionária que não é exibida. A razão da diferença fracionária é que os números de ponto flutuante são representados no computador em pequenas etapas fracionárias, e assim representar o número inteiro exatamente seria uma coincidência. Portanto, embora o número inteiro exibido como flutuação seja o mesmo que foi digitado, a tela pode ser uma aproximação do que é armazenado.

Classificação de conversão inteira

Qualquer tipo inteiro tem uma classificação que foi dada a ele. Este ranking ajuda na conversão. A classificação é relativa; as fileiras não estão em níveis fixos. Exceto Char e Char assinado, não há dois números inteiros assinados a mesma classificação (assumindo que o char está assinado). Os tipos inteiros não assinados têm o mesmo ranking que seus tipos inteiros assinados correspondentes. A classificação é a seguinte:

  • Supondo que Char seja assinado, Char e Char assinados têm a mesma classificação.
  • A classificação de um tipo inteiro assinado é maior que a classificação de um tipo inteiro assinado de um número menor de bytes de armazenamento. Portanto, o posto de Int Long Long é maior que o posto de Int Long Long, que é maior que o posto de Int assinado, que é maior que o posto de Int Short Surpreted, que é maior que o posto de char assinado.
  • A classificação de qualquer tipo inteiro não assinado é igual à classificação do tipo inteiro assinado correspondente.
  • O posto de char não assinado é igual ao posto de char assinado.
  • Bool tem a menor classificação; sua classificação é menor que a do char assinado.
  • char16_t tem a mesma classificação que o curto int. char32_t tem a mesma classificação que o int. Para o compilador G ++, Wchar_T tem a mesma classificação que o INT.

Promoções integrais

Promoções integrais são promoções inteiras. Não há razão para que um número inteiro de menos bytes não possa ser representado por um número inteiro de bytes maiores. Promoções inteiras lida com tudo o que se segue:

  • Um Int curto assinado (dois bytes) pode ser convertido em um INT assinado (quatro bytes). Um curto Int não assinado (dois bytes) pode ser convertido em um int não assinado (quatro bytes). NOTA: A conversão de um INT curto em um INT longo ou um longo e longo leva a um desperdício de armazenamento (localização do objeto) bytes e um desperdício de memória. Bool, char16_t, char32_t e wchar_t estão isentos desta promoção (com o compilador g ++, char32_t e wchar_t têm o mesmo número de bytes).
  • Com o compilador G ++, um tipo CHAR16_T pode ser convertido em um tipo int assinado ou um tipo int não assinado; Um tipo de char32_t pode ser convertido em um tipo int assinado ou um tipo int não assinado; e um tipo wchar_t pode ser convertido em um tipo int assinado ou não assinado.
  • Um tipo bool pode ser convertido em um tipo int. Nesse caso, True se torna 1 (quatro bytes) e False se torna 0 (quatro bytes). Int pode ser assinado ou assinado.
  • Promoção inteira também existe para o tipo de enumeração não escondido - veja mais adiante.

Conversões aritméticas usuais

Considere o seguinte código:

flutuar f = 2.5;
int i = f;
cout<O código compila sem indicar nenhum aviso ou erro, dando a saída de 2, o que provavelmente não é o que era esperado. = é um operador binário porque leva um operando esquerdo e direito. Considere o seguinte código:

int i1 = 7;
int i2 = 2;
float flt = i1 / i2;
cout<A saída é 3, Mas isso está errado; Era suposto ser 3.5. O operador da divisão, /, também é um operador binário.

C ++ tem conversões aritméticas usuais que o programador deve saber para evitar erros na codificação. As conversões aritméticas usuais em operadoras binárias são as seguintes:

  • Se um operando for do tipo “Long Double”, então o outro será convertido para o dobro longo.
  • Caso contrário, se um operando for duplo, o outro será convertido para dobrar.
  • Caso contrário, se um operando estiver flutuando, o outro será convertido para flutuar. No código acima, o resultado de i1/i2 é oficialmente 2; É por isso que FLT é 2. O resultado do binário, /, é aplicado como o operando direito ao operador binário, = =. Portanto, o valor final de 2 é um flutuador (não um int).

Caso contrário, a promoção inteira ocorreria da seguinte maneira:

  • Se ambos os operandos forem do mesmo tipo, não ocorre mais conversão.
  • Caso contrário, se ambos os operandos forem assinados tipos inteiros ou ambos forem tipos inteiros não assinados, o operando do tipo com a classificação inteira inferior será convertida para o tipo de operando com a classificação mais alta.
  • Caso contrário, se um operando for assinado e o outro não assinar, e se o tipo de operando não assinado for maior ou igual à classificação do tipo de operando assinado e se o valor do operando assinado for maior ou igual a zero, então O operando assinado será convertido para o tipo de operando não assinado (com o alcance levado em consideração). Se o operando assinado for negativo, o compilador seguirá um algoritmo e retornará um número que pode não ser aceitável para o programador.
  • Caso contrário, se um operando é do tipo inteiro assinado e o outro for um tipo inteiro não assinado, e se todos os valores possíveis do tipo do operando com o tipo inteiro não assinado puderem ser representados pelo tipo inteiro assinado, o tipo inteiro não assinado irá ser convertido para o tipo de operando do tipo inteiro assinado.
  • Caso contrário, os dois operando (um char e um bool, por exemplo) seriam convertidos para o tipo inteiro não assinado.

Promoção de ponto flutuante

Os tipos de ponto flutuante incluem "Float", "Double" e "Long Double.”Um tipo de ponto flutuante deve ter pelo menos a mesma precisão que seu antecessor. A promoção de ponto flutuante permite a conversão de flutuação para dobrar ou de dobro para longo duplo.

Conversões de ponteiro

Um ponteiro de um tipo de objeto não pode ser atribuído a um ponteiro de um tipo de objeto diferente. O código a seguir não será compilação:

int id = 6;
int* intptr = &id;
Float IDF = 2.5;
Float* floatptr = &idf;
intptr = floatptr; // erro aqui

Um ponteiro nulo é um ponteiro cujo valor de endereço é zero. Um ponteiro nulo de um tipo de objeto não pode ser atribuído a um ponteiro nulo de um tipo de objeto diferente. O código a seguir não será compilação:

int id = 6;
int* intptr = &id;
intptr = 0;
Float IDF = 2.5;
Float* floatptr = &idf;
floatptr = 0;
intptr = floatptr; // erro aqui

Um ponteiro nulo const de um tipo de objeto não pode ser atribuído a um ponteiro nulo const de um tipo de objeto diferente. O código a seguir não será compilação:

int id = 6;
int* intptr = &id;
int* const intpc = 0;
Float IDF = 2.5;
Float* floatptr = &idf;
Float* const floatpc = 0;
intpc = floatpc; // erro aqui

Um ponteiro nulo pode receber um valor de endereço diferente para seu tipo. O código a seguir ilustra o seguinte:

Float IDF = 2.5;
float* floatptr = 0;
floatptr = &idf;
cout<<*floatPtr<<'\n';

A saída é 2.5.

Como esperado, uma constante de ponteiro nulo não pode receber nenhum valor de endereço de seu tipo. O código a seguir não será compilação:

Float IDF = 2.5;
Float* const floatpc = 0;
floatpc = &idf; // erro aqui

No entanto, um ponteiro nulo constante pode ser atribuído a um ponteiro comum, mas do mesmo tipo (isso é esperado). O código a seguir ilustra o seguinte:

Float IDF = 2.5;
Float* const floatpc = 0;
Float* floatpter = &idf;
floatpter = floatpc; //OK
cout << floatPter << '\n';

A saída é 0.

Dois valores de ponteiro nulo do mesmo tipo compare (==) iguais.

Um ponteiro para um tipo de objeto pode ser atribuído a um ponteiro para anular. O código a seguir ilustra o seguinte:

Float IDF = 2.5;
Float* floatptr = &idf;
void* vd;
vd = floatptr;

O código compila sem uma mensagem de aviso ou erro.

Função para conversões de ponteiro

Um ponteiro para uma função que não lançaria uma exceção pode ser atribuída a um ponteiro para funcionar. O código a seguir ilustra o seguinte:

#incluir
usando namespace std;
void fn1 () noexcept

cout << "with noexcept" << '\n';

void fn2 ()

//declarações

void (*func1) () NoExcept;
void (*func2) ();
int main ()

func1 = &fn1;
func2 = &fn2;
func2 = &fn1;
func2 ();
retornar 0;

A saída é com NoExcept.

Conversões booleanas

Em C ++, entidades que podem resultar em false incluem "zero", "ponteiro nulo" e "ponteiro de membro nulo.“Todas as outras entidades resultam em verdadeiro. O código a seguir ilustra o seguinte:

bool a = 0.0; cout << a <<'\n';
float* floatptr = 0;
bool b = floatptr; cout << b <<'\n';
bool c = -2.5; cout << c <<'\n';
bool d = +2.5; cout << d <<'\n';

A saída é:

0 // para falso
0 // para falso
1 // para verdadeiro
1 // para verdadeiro

Lvalue, prvalue e xvalue

Considere o seguinte código:

int id = 35;
int & id1 = id;
cout << id1 << '\n';

A saída é 35. No código, ID e ID1 são lvalues ​​porque identificam um local (objeto) na memória. A saída 35 é um prvalue. Qualquer literal, exceto um literal de corda, é um prvalue. Outros prvalos não são tão óbvios, como nos exemplos que se seguem. Considere o seguinte código:

int id = 62;
int* ptr = &id;
int* pter;

PTR é um lvalue porque identifica um local (objeto) na memória. Por outro lado, Pter não é um lvalue. Pter é um ponteiro, mas não identifica nenhum local na memória (não está apontando para nenhum objeto). Então, Pter é um prvalue.

Considere o seguinte código:

void fn ()

//declarações

void (*func) () = &fn;
float (*functn) ();

Fn () e (*func) () são expressões de lvalue porque identificam uma entidade (função) na memória. Por outro lado, (*functn) () não é uma expressão de LValue. (*functn) () é um ponteiro para uma função, mas não identifica nenhuma entidade na memória (não está apontando para nenhuma função na memória). Então, (*functn) () é uma expressão de prvalue.

Agora, considere o seguinte código:

estruturas s

int n;
;
S obj;

S é uma classe e obj é um objeto instanciado da classe. OBJ identifica um objeto na memória. Uma aula é uma unidade generalizada. Então, S realmente não identifica nenhum objeto na memória. S diz que é um objeto sem nome. S também é uma expressão de prvalue.

O foco deste artigo está em prvalos. Prvvalue significa rvalue puro.

Xvalue

XValue significa o valor expirador. Valores temporários estão expirando valores. Um lvalue pode se tornar um xvalue. Um prvalue também pode se tornar um XValue. O foco deste artigo está em prvalos. Um XValue é um LValue ou uma referência de Rvalue sem nome cujo armazenamento pode ser reutilizado (geralmente porque está próximo ao final de sua vida). Considere o seguinte código que funciona:

estruturas s

int n;
;
int q = s ().n;

A expressão “int q = s ().n; ” cópias qualquer que seja o valor que n mantém para q. S () é apenas um meio; não é uma expressão usada regularmente. S () é um prvalue cujo uso o converteu em um xvalue.

Conversões de LValue-para-avaliação

Considere a seguinte declaração:

int ii = 70;

70 é um prvalue (rvalue) e II é um lvalue. Agora, considere o seguinte código:

int ii = 70;
int tt = ii;

Na segunda declaração, II está na situação de um prvalue, então II se torna um prvalor. Em outras palavras, o compilador converte II em um prvalue implicitamente. Ou seja, quando um LValue é usado em uma situação em que a implementação espera um Prvalue, a implementação converte o LValue em um Prvalue.

Conversões de matriz a ponte

Considere o seguinte código que funciona:

char* p;
char q [] = 'a', 'b', 'c';
p = & q [0];
++p;
cout<<*p<<'\n';

A saída é b. A primeira afirmação é uma expressão e é um ponteiro para um personagem. Mas para qual personagem é a declaração apontando? - Nenhum personagem. Então, é um prvalue e não um lvalue. A segunda declaração é uma matriz em que q [] é uma expressão de lvalue. A terceira declaração transforma o prvalue, p, em uma expressão de LValue, que aponta para o primeiro elemento da matriz.

Conversões de função a ponto

Considere o seguinte programa:

#incluir
usando namespace std;
void (*func) ();
void fn ()

//declarações

int main ()

func = &fn;
retornar 0;

A expressão “void (*func) ();” é um ponteiro para uma função. Mas para qual função é a expressão apontando? - Sem função. Então, é um prvalue e não um lvalue. Fn () é uma definição de função, onde fn é uma expressão de lvalue. Em main (), “func = &fn;”Transforma o prvalue, func, em uma expressão de LValue que aponta para a função, fn ().

Conversões de materialização temporária

Em C ++, um Prvvalue pode ser convertido em um XValue do mesmo tipo. O código a seguir ilustra o seguinte:

estruturas s

int n;
;
int q = s ().n;

Aqui, o Prvvalue, S (), foi convertido em um XValue. Como XValue, não duraria muito - veja mais explicação acima.

Conversões de qualificação

Um tipo qualificado por CV é um tipo qualificado pela palavra reservada, “const” e/ou a palavra reservada, “volátil.”

Qualificação CV também é classificada. Nenhuma qualificação de CV é menor que a qualificação "const", que é menor que a qualificação "const volátil". Nenhuma qualificação de CV é menor que a qualificação "volátil", que é menor que a qualificação "const volátil". Então, existem dois fluxos de classificação de qualificação. Um tipo pode ser mais qualificado pelo CV do que outro.

Um tipo mais baixo de prvalue cv que pode ser convertido em um tipo prvalue mais qualificado para CV. Ambos os tipos devem ser ponteiros para CV.

Conclusão

As entidades C ++ podem ser convertidas de um tipo para um tipo relacionado implicitamente ou explicitamente. No entanto, o programador deve entender o que pode ser convertido e o que não pode ser convertido, e em que forma. A conversão pode ocorrer nos seguintes domínios: conversões integrais, conversões de ponto flutuante, conversões de integral flutuante, conversões aritméticas usuais, conversões de ponteiro, conversões de ponteiro, conversões booleanas, conversões de Lvalue-para-avaliação, conversões de matriz para ponto , Conversões de função a ponte, conversões de materialização temporária e conversões de qualificação.