C ++

Conversões padrão C ++

Conversões padrão C ++
Existem dois tipos de entidade em C ++, os tipos fundamentais e os tipos compostos. Os tipos fundamentais são os tipos escalares. Os tipos compostos são os demais tipos de entidade. A conversão pode ocorrer de um tipo de entidade para outro tipo apropriado. Considere o seguinte programa:

#incluir
#incluir
usando namespace std;
int main ()

int rt1 = sqrt (5);
int rt2 = sqrt (8);
cout<return 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. Portanto, as duas primeiras declarações no a Principal() função reduziu as respostas da raiz quadrada de 5 e da raiz quadrada de 8. Este artigo não discute piso ou 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 feito, perda de precisão ou restrição adicionada ou removida. Conhecimento básico de C ++ é um pré-requisito para entender este artigo.

Conteúdo do Artigo

  • Conversões Integrais
  • Conversões de ponto flutuante
  • Conversões Integrais Flutuantes
  • Classificação de conversão de inteiro
  • Promoções Integral
  • 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 valor em valor
  • Conversões de matriz para ponteiro
  • Conversões de função para ponteiro
  • Conversões de Materialização Temporárias
  • Conversões de qualificação
  • Conclusão

Conversões Integrais

Conversões integrais são conversões inteiras. Inteiros não assinados incluem “unsigned char”, “unsigned short int,” “unsigned int,” “unsigned long int,” e “unsigned long long int.”Os inteiros assinados correspondentes incluem“ sinal assinado ”,“ short int, ”“ int, ”“ long int, ”e“ long long int.”Cada tipo de 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 qualquer problema. O problema ocorre ao converter de um tipo de intervalo maior para um tipo de intervalo menor ou ao converter um número com sinal em um número sem sinal correspondente.

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

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

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

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

int a = -27647;
float b = 2.5;
int c = 0;
bool a1 = a;
bool b1 = b;
bool c1 = c;
cout<cout<cout<O resultado é:

1 para verdade
1 para verdade
0 para falso

Conversões de ponto flutuante

Os tipos de vírgula flutuante incluem "float", "double" e "long double.”Tipos de ponto flutuante não são agrupados em assinados e não assinados, como 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 de seu predecessor. Ou seja, “long double” deve ter precisão igual ou maior que “double” e “double” deve ter precisão igual ou maior para “float.”

Lembre-se de que o intervalo de um tipo de ponto flutuante não é contínuo; em vez disso, é em pequenos passos. Quanto maior for a precisão do tipo, menores serão as etapas e maior será o número de bytes para armazenar o número. Portanto, quando um número de ponto flutuante é convertido de um tipo de menor precisão para um tipo de maior precisão, o programador deve aceitar um falso aumento 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 superior para um tipo de precisão inferior, o programador deve aceitar uma perda de precisão. Se o número de bytes para armazenamento de números deve ser reduzido, então o compilador seguirá algum algoritmo e retornará um número como um substituto (o que provavelmente não é o que o programador deseja). Além disso, tenha em mente os problemas fora de alcance.

Conversões Integrais Flutuantes

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

float f = 56.953;
int i = f;
cout<A saída é 56. Os intervalos de float e inteiro devem ser compatíveis.

Quando um inteiro é convertido em um número flutuante, o valor exibido como um número flutuante é o mesmo que foi digitado como um número inteiro. No entanto, o equivalente flutuante pode ser o valor exato ou ter uma pequena diferença fracionária que não é exibida. A razão para a diferença fracionária é que os números de ponto flutuante são representados no computador em pequenos passos fracionários e, portanto, representar o inteiro exatamente seria uma coincidência. Portanto, embora o número inteiro exibido como flutuante seja o mesmo que foi digitado, a exibição pode ser uma aproximação do que está armazenado.

Classificação de conversão de inteiro

Qualquer tipo inteiro tem uma classificação que foi dada a ele. Esta classificação ajuda na conversão. A classificação é relativa; as classificações não estão em níveis fixos. Exceto para char e sinalizado, não há dois inteiros assinados com a mesma classificação (assumindo que char é assinado). Tipos inteiros sem sinal têm a mesma classificação de seus tipos inteiros com sinais correspondentes. A classificação é a seguinte:

  • Assumindo que char está assinado, char e assinado char têm a mesma classificação.
  • A classificação de um tipo inteiro com sinal é maior do que a classificação de um tipo inteiro com sinal de um número menor de bytes de armazenamento. Portanto, a classificação do int longo assinado é maior que a classificação do int longo assinado, que é maior do que a classificação do int assinado, que é maior do que a classificação do int curto assinado, que é maior do que a classificação do char assinado.
  • A classificação de qualquer tipo inteiro sem sinal é igual à classificação do tipo inteiro com sinal correspondente.
  • A classificação de unsigned char é igual à classificação de sinalizado char.
  • bool tem a classificação mais baixa; sua classificação é menor que a de char assinado.
  • char16_t tem a mesma classificação do short 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 Integral

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. O Integer Promotions trata de tudo o que se segue:

  • Um int curto assinado (dois bytes) pode ser convertido em um int assinado (quatro bytes). Um int curto sem sinal (dois bytes) pode ser convertido em um int sem sinal (quatro bytes). Observação: converter um int curto em um int longo ou um int longo longo leva a um desperdício de bytes de armazenamento (localização do objeto) 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 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. Neste caso, verdadeiro se torna 1 (quatro bytes) e falso se torna 0 (quatro bytes). O int pode ser assinado ou assinado.
  • A promoção de número inteiro também existe para o tipo de enumeração sem escopo - veja mais tarde.

Conversões aritméticas usuais

Considere o seguinte código:

float f = 2.5;
int i = f;
cout<O código compila sem indicar qualquer 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 à esquerda e à direita. 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 de 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 operadores binários são as seguintes:

  • Se qualquer um dos operandos for do tipo "duplo longo", o outro será convertido para duplo longo.
  • Caso contrário, se um dos operandos for duplo, o outro será convertido para duplo.
  • Caso contrário, se um dos operandos for float, o outro será convertido para float. 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 certo ao operador binário, =. Portanto, o valor final de 2 é um float (não um int).

OUTRO, A PROMOÇÃO INTEIRA ACONTECERIA DA SEGUINTE MESMA:

  • Se ambos os operandos forem do mesmo tipo, nenhuma conversão ocorrerá.
  • Caso contrário, se ambos os operandos forem tipos inteiros com sinal ou ambos forem tipos inteiros sem sinal, então o operando do tipo com a classificação inteira mais baixa será convertido para o tipo de operando com a classificação mais alta.
  • Caso contrário, se um operando for assinado e o outro não, 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 intervalo 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 é um tipo inteiro com sinal e o outro é um tipo inteiro sem sinal, e se todos os valores possíveis do tipo do operando com o tipo inteiro sem sinal podem ser representados pelo tipo inteiro sem sinal, então o tipo inteiro sem sinal ser convertido para o tipo de operando do tipo inteiro com sinal.
  • Caso contrário, os dois operandos (um char e um bool, por exemplo) seriam convertidos para o tipo inteiro sem sinal.

Promoção de ponto flutuante

Os tipos de vírgula flutuante incluem "float", "double" e "long double.”Um tipo de ponto flutuante deve ter pelo menos a mesma precisão de seu predecessor. A promoção de ponto flutuante permite a conversão de float para double ou de double para long double.

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á compilado:

id int = 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á compilado:

id int = 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á compilado:

id int = 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 isso:

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 ser atribuída a nenhum valor de endereço de seu tipo. O código a seguir não será compilado:

float idf = 2.5;
float * const floatPC = 0;
floatPC = &idf; // erro aqui

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

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 comparam (==) igual.

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

float idf = 2.5;
float * floatPtr = &idf;
void * vd;
vd = floatPtr;

O código é compilado sem um aviso ou mensagem de 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ído a um ponteiro para a função. O código a seguir ilustra isso:

#incluir
usando namespace std;
void fn1 () noexcept

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

void fn2 ()

//afirmações

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

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

A saída é com nenhuma exceção.

Conversões Booleanas

Em C ++, as entidades que podem resultar em falso incluem “zero”, “ponteiro nulo” e “ponteiro de membro nulo.”Todas as outras entidades resultam em verdadeiras. O código a seguir ilustra isso:

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';

O resultado é:

0 // para falso
0 // para falso
1 // para verdade
1 // para verdade

Lvalue, prvalue e xvalue

Considere o seguinte código:

id int = 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 string, é um prvalue. Outros pré-valores não são tão óbvios, como nos exemplos a seguir. Considere o seguinte código:

id int = 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 aponta para nenhum objeto). Então, pter é um prvalue.

Considere o seguinte código:

void fn ()

//afirmações

void (* func) () = &fn;
float (* função) ();

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 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). Portanto, (* functn) () é uma expressão prvalue.

Agora, considere o seguinte código:

struct S

int n;
;
S obj;

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

O foco deste artigo está nos prvalues. Prvalue significa rvalue puro.

Xvalue

Xvalue significa Valor Expirante. Valores temporários são valores expirados. Um lvalue pode se tornar um xvalue. Um prvalue também pode se tornar um xvalue. O foco deste artigo está nos prvalues. Um xvalue é um lvalue ou uma referência rvalue sem nome cujo armazenamento pode ser reutilizado (geralmente porque está próximo do final de sua vida útil). Considere o seguinte código que funciona:

struct S

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

A expressão “int q = S ().n; ” copia qualquer valor que n conté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 valor em valor

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 afirmação, ii está na situação de um prvalue, então ii torna-se um prvalue lá. 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 para ponteiro

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 declaração é uma expressão e é um ponteiro para um caractere. Mas para qual personagem a declaração está apontando? - Sem personagem. Então, é um prvalue e não um lvalue. A segunda declaração é uma matriz em que q [] é uma expressão lvalue. A terceira instrução transforma o prvalue, p, em uma expressão lvalue, que aponta para o primeiro elemento da matriz.

Conversões de função para ponteiro

Considere o seguinte programa:

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

//afirmações

int main ()

func = &fn;
return 0;

A expressão “void (* func) ();” é um ponteiro para uma função. Mas para qual função a expressão está 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 lvalue que aponta para a função, fn ().

Conversões de Materialização Temporárias

Em C ++, um prvalue pode ser convertido em um xvalue do mesmo tipo. O código a seguir ilustra isso:

struct S

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

Aqui, o prvalue, S (), foi convertido para um xvalue. Como um valor x, não duraria muito - veja mais explicação acima.

Conversões de qualificação

Um tipo cv qualificado é um tipo qualificado pela palavra reservada, "const" e / ou pela palavra reservada, "volátil.”

A qualificação Cv também é classificada. Nenhuma qualificação cv é menor que a qualificação "const", que é menor que a qualificação "const volatile". Nenhuma qualificação cv é menor que a qualificação "volátil", que é menor que a qualificação "const volatile". Portanto, existem dois fluxos de classificação de qualificação. Um tipo pode ser mais qualificado para CV do que outro.

Um tipo de cv qualificado de prvalue inferior pode ser convertido para um tipo de prvalue mais qualificado de cv. Ambos os tipos devem ser apontadores para cv.

Conclusão

As entidades C ++ podem ser convertidas de um tipo para um tipo relacionado implícita 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 integrais flutuantes, Conversões aritméticas usuais, Conversões de ponteiro, Conversões de função para ponteiro, Conversões booleanas, Conversões de valor para rvalue, Conversões de vetor para ponteiro , Conversões de Função para Ponteiro, Conversões de Materialização Temporária e Conversões de Qualificação.

O botão esquerdo do mouse não funciona no Windows 10
Se você estiver usando um mouse dedicado com seu laptop ou computador desktop, mas o o botão esquerdo do mouse não funciona no Windows 10/8/7 por algu...
O cursor pula ou se move aleatoriamente enquanto digita no Windows 10
Se você descobrir que o cursor do mouse pula ou se move por conta própria, de forma automática e aleatória ao digitar em um laptop ou computador com W...
Como reverter a direção de rolagem do Mouse e Touchpads no Windows 10
Mouse e Touchpads não apenas torna a computação mais fácil, mas mais eficiente e menos demorada. Não podemos imaginar uma vida sem esses dispositivos,...