Regras de conversão de tipo implícito em operadores C ++

Eu quero ser melhor em saber quando devo lançar. Quais são as regras de conversão de tipo implícito em C ++ ao adicionar, multiplicar, etc. Por exemplo,

int + float = ? int * float = ? float * int = ? int / float = ? float / int = ? int / int = ? int ^ float = ? 

et cetera …

A expressão será sempre avaliada como o tipo mais preciso? As regras diferem para o Java? Por favor, corrija-me se eu tiver redigido esta questão de forma imprecisa.

    Em operadores C ++ (para tipos POD) sempre atuam em objects do mesmo tipo.
    Assim, se eles não são os mesmos, serão promovidos para coincidir com o outro.
    O tipo do resultado da operação é o mesmo dos operandos (após a conversão).

     If either is long double the other is promoted to long double If either is double the other is promoted to double If either is float the other is promoted to float If either is long long unsigned int the other is promoted to long long unsigned int If either is long long int the other is promoted to long long int If either is long unsigned int the other is promoted to long unsigned int If either is long int the other is promoted to long int If either is unsigned int the other is promoted to unsigned int If either is int the other is promoted to int Both operands are promoted to int 

    Nota. O tamanho mínimo das operações é int . Então short / char são promovidos para int antes que a operação seja feita.

    Em todas as suas expressões, o int é promovido a um float antes que a operação seja executada. O resultado da operação é um float .

     int + float => float + float = float int * float => float * float = float float * int => float * float = float int / float => float / float = float float / int => float / float = float int / int = int int ^ float =>  

    Operações aritméticas envolvendo float resultam em float .

     int + float = float int * float = float float * int = float int / float = float float / int = float int / int = int 

    Para mais detalhes, responda. Veja o que a seção §5 / 9 do padrão C ++ diz

    Muitos operadores binários que esperam operandos de tipo aritmético ou de enumeração causam conversões e geram tipos de resultados de maneira semelhante. O objective é produzir um tipo comum, que também é o tipo do resultado .

    Esse padrão é chamado de conversões aritméticas usuais, que são definidas da seguinte maneira:

    – Se um dos operandos for do tipo long double, o outro será convertido em double long.

    – Caso contrário, se um dos operandos for duplo, o outro será convertido em double.

    – Caso contrário, se um dos operandos for float, o outro será convertido em float.

    – Caso contrário, as promoções integrais (4.5) serão realizadas em ambos os operandos.54)

    – Então, se um dos operandos não estiver assinado, o outro deve ser convertido em longo sem sinal.

    – Caso contrário, se um operando for um int longo e o outro unsigned int, então, se um int longo puder representar todos os valores de um int não assinado, o int não assinado será convertido em um int longo; caso contrário, ambos os operandos devem ser convertidos em unsigned long int.

    – Caso contrário, se um dos operandos for longo, o outro será convertido em longo.

    – Caso contrário, se um dos operandos não estiver assinado, o outro será convertido em não assinado.

    [Nota: caso contrário, o único caso restante é que ambos os operandos são int]

    Como as outras respostas não falam sobre as regras do C ++ 11, aqui está uma. Do padrão C ++ 11 (versão n3337) §5 / 9:

    Esse padrão é chamado de conversões aritméticas usuais , que são definidas da seguinte maneira:

    – Se um dos operandos for do tipo de enumeração com escopo definido, nenhuma conversão será executada; se o outro operando não tiver o mesmo tipo, a expressão será mal formada.

    – Se um dos operandos for do tipo long double, o outro será convertido em double long.

    – Caso contrário, se um dos operandos for duplo, o outro será convertido em double.

    – Caso contrário, se um dos operandos for float, o outro será convertido em float.

    – Caso contrário, as promoções integrais serão realizadas em ambos os operandos. Em seguida, as seguintes regras devem ser aplicadas aos operandos promovidos:

    – Se os dois operandos tiverem o mesmo tipo, nenhuma conversão adicional será necessária.

    – Caso contrário, se os dois operandos tiverem tipos inteiros assinados ou ambos tiverem tipos inteiros sem sinal, o operando com o tipo de sorting de conversão de número inteiro menor será convertido para o tipo de operando com maior sorting.

    – Caso contrário, se o operando que possui tipo inteiro não assinado tiver posto maior ou igual ao rank do tipo do outro operando, o operando com o tipo inteiro assinado deverá ser convertido para o tipo do operando com o tipo inteiro sem sinal.

    – Caso contrário, se o tipo do operando com o tipo inteiro assinado puder representar todos os valores do tipo do operando com o tipo inteiro sem sinal, o operando com o tipo inteiro não assinado deve ser convertido para o tipo do operando com o tipo inteiro assinado.

    – Caso contrário, ambos os operandos serão convertidos para o tipo inteiro sem sinal correspondente ao tipo do operando com o tipo inteiro assinado.

    Veja aqui uma lista atualizada com freqüência.

    Esta resposta é dirigida em grande parte em um comentário feito por @ RafałDowgird:

    “O tamanho mínimo das operações é int.” – Isso seria muito estranho (e as arquiteturas que suportam eficientemente operações de char / short?) Isso é realmente na especificação do C ++?

    Tenha em mente que o padrão C ++ possui a importantíssima regra “como se”. Veja a seção 1.8: Execução do Programa:

    3) Esta provisão é às vezes chamada de regra “como se”, porque uma implementação é livre para desconsiderar qualquer exigência do Padrão, desde que o resultado seja como se o requerimento tivesse sido obedecido, até onde pode ser determinado pelo observável. comportamento do programa.

    O compilador não pode definir um int para ter 8 bits de tamanho, mesmo que seja o mais rápido, já que o padrão exige um mínimo de 16 bits int .

    Portanto, no caso de um computador teórico com operações super rápidas de 8 bits, a promoção implícita para int para aritmética poderia importar. No entanto, para muitas operações, você não pode dizer se o compilador realmente executou as operações na precisão de um int e depois converteu em um char para armazenar em sua variável, ou se as operações foram feitas em char o tempo todo.

    Por exemplo, considere unsigned char = unsigned char + unsigned char + unsigned char , onde a adição estouraria (vamos supor um valor de 200 para cada). Se você promovesse a int , você obteria 600, que seriam então convertidos implicitamente em um unsigned char , o que envolveria o módulo 256, resultando em um resultado final de 88. Se você não fizesse tais promoções, teria que finalizar entre as duas primeiras adições, o que reduziria o problema de 200 + 200 + 200 para 144 + 200 , que é 344, o que reduz para 88. Em outras palavras, o programa não sabe a diferença, então o compilador está livre para ignorar o mandato para executar operações intermediárias em int se os operandos tiverem uma sorting mais baixa que int .

    Isto é verdade em geral de adição, subtração e multiplicação. Não é verdade em geral para divisão ou módulo.

    Se você excluir os tipos não assinados, haverá uma hierarquia ordenada: char assinado, short, int, long, long long, float, double, long double. Primeiro, qualquer coisa vinda antes do int no acima será convertida para int. Em seguida, em uma operação binária, o tipo de sorting inferior será convertido para o mais alto e os resultados serão o tipo de maior. (Você notará que, a partir da hierarquia, sempre que um ponto flutuante e um tipo integral estiverem envolvidos, o tipo integral será convertido para o tipo de ponto flutuante.)

    Unsigned complica um pouco as coisas: perturba o ranking e partes do ranking tornam-se definidas pela implementação. Por causa disso, é melhor não misturar assinado e não assinado na mesma expressão. (A maioria dos especialistas em C ++ parece evitar o envio de assinatura, a menos que operações bit a bit estejam envolvidas. Isso é, pelo menos, o que a Stroustrup recomenda).

    Minha solução para o problema tem WA (resposta errada), então mudei um int para long long int e deu AC (accept) . Anteriormente, eu estava tentando fazer long long int += int * int , e depois eu corrigi-lo para long long int += long long int * int . Pesquisando eu inventei,

    1. Conversões Aritméticas

    Condições para conversão de tipo:

    Condições atendidas —> Conversão

    • Um dos operandos é do tipo long double . —> Outro operando é convertido para tipo double longo .

    • Condição precedente não atendida e o operando é do tipo double . —> Outro operando é convertido no tipo double .

    • Condições precedentes não atendidas e o operando é do tipo float . —> Outro operando é convertido no tipo float .

    • Condições precedentes não atendidas (nenhum dos operandos é de tipos flutuantes). —> Promoções integrais são executadas nos operandos da seguinte forma:

      • Se um dos operandos for do tipo unsigned long , o outro operando será convertido para o tipo unsigned long .
      • Se a condição precedente não for atendida e se o operando for do tipo longo e o outro do tipo unsigned int , ambos os operandos serão convertidos para o tipo unsigned long .
      • Se as duas condições precedentes não forem atendidas, e se um dos operandos for do tipo longo , o outro operando será convertido para o tipo longo .
      • Se as três condições anteriores não forem atendidas e se um dos operandos for do tipo unsigned int , o outro operando será convertido para o tipo unsigned int .
      • Se nenhuma das condições anteriores for atendida, ambos os operandos serão convertidos para o tipo int .

    2 Regras de conversão de números inteiros

    • Promoções inteiras:

    Tipos inteiros menores que int são promovidos quando uma operação é executada neles. Se todos os valores do tipo original puderem ser representados como um int, o valor do tipo menor será convertido em um int; caso contrário, ele será convertido em um int não assinado. Promoções inteiras são aplicadas como parte das conversões aritméticas usuais para certas expressões de argumento; operandos dos operadores unários +, – e ~; e operandos dos operadores de turno.

    • Classificação de conversão inteira:

      • Não há dois tipos inteiros assinados devem ter a mesma sorting, mesmo que tenham a mesma representação.
      • A sorting de um tipo inteiro assinado deve ser maior que a sorting de qualquer tipo inteiro assinado com menos precisão.
      • O posto de long long int será maior que o rank de long int , que será maior que o rank de int , que será maior do que o rank de short int , que será maior do que o rank de signed char .
      • A sorting de qualquer tipo de inteiro não assinado deve ser igual à sorting do tipo inteiro assinado assinado correspondente, se houver.
      • A sorting de qualquer tipo inteiro padrão deve ser maior que a sorting de qualquer tipo inteiro estendido com a mesma largura.
      • A sorting de char será igual à sorting de signed char e unsigned char .
      • A sorting de qualquer tipo de número inteiro assinado estendido em relação a outro tipo de número inteiro assinado estendido com a mesma precisão é definida pela implementação, mas ainda sujeita às outras regras para determinar a sorting de conversão de número inteiro.
      • Para todos os tipos inteiros T1, T2 e T3, se T1 tiver maior sorting que T2 e T2 tiver maior sorting que T3, então T1 terá maior sorting que T3.
    • Conversões aritméticas usuais:

      • Se os dois operandos tiverem o mesmo tipo, nenhuma conversão adicional será necessária.
      • Se os dois operandos forem do mesmo tipo inteiro (assinados ou não assinados), o operando com o tipo de sorting de conversão de número inteiro menor será convertido para o tipo de operando com maior sorting.
      • Se o operando que possui um tipo inteiro sem sinal tiver uma sorting maior ou igual à sorting do tipo do outro operando, o operando com o tipo inteiro assinado será convertido para o tipo do operando com o tipo inteiro não assinado.
      • Se o tipo do operando com o tipo inteiro assinado puder representar todos os valores do tipo do operando com o tipo inteiro sem sinal, o operando com o tipo inteiro não assinado é convertido para o tipo do operando com o tipo inteiro assinado.
      • Caso contrário, ambos os operandos são convertidos para o tipo inteiro sem sinal correspondente ao tipo do operando com o tipo inteiro assinado. Operações específicas podem adicionar ou modificar a semântica das operações aritméticas usuais.

    Todo o capítulo 4 fala sobre conversões, mas acho que você deveria estar mais interessado nestes:

    4.5 Promoções integrais [conv.prom]
    Um rvalue de tipo char, char assinado, unsigned char, short int ou unsigned short int pode ser convertido em um rvalue do tipo int se int puder representar todos os valores do tipo de origem; de outros-
    sábio, o rvalor de origem pode ser convertido em um rvalue do tipo unsigned int.
    Um rvalor do tipo wchar_t (3.9.1) ou um tipo de enumeração (7.2) pode ser convertido em um rvalue do primeiro
    dos tipos a seguir que podem representar todos os valores de seu tipo subjacente: int, unsigned int,
    longa ou longa sem assinatura.
    Um rvalue para um campo de bits integral (9.6) pode ser convertido para um rvalor do tipo int se int puder representar todos
    os valores do campo de bits; caso contrário, ele pode ser convertido em int não assinado se int não assinado puder
    reenvie todos os valores do campo de bits. Se o campo de bits for maior ainda, nenhuma promoção integral será aplicada a ele. Se o
    bit-field tem um tipo enumerado, é tratado como qualquer outro valor desse tipo para propósitos de promoção.
    Um rvalue do tipo bool pode ser convertido em um rvalue do tipo int, com false se tornando zero e true
    tornando-se um.
    Essas conversões são chamadas de promoções integrais.

    4.6 Promoção do ponto flutuante [conv.fpprom]
    Um rvalue do tipo float pode ser convertido em um rvalue do tipo double. O valor é inalterado.
    Essa conversão é chamada de promoção de ponto flutuante.

    Portanto, todas as conversões envolvendo float – o resultado é float.

    Apenas o que envolve os dois int – o resultado é int: int / int = int

    O tipo da expressão, quando não ambas as partes são do mesmo tipo, será convertido para o maior de ambos. O problema aqui é entender qual é maior que o outro (não tem nada a ver com tamanho em bytes).

    Em expressões nas quais um número real e um número inteiro estão envolvidos, o inteiro será promovido para o número real. Por exemplo, em int + float, o tipo da expressão é float.

    A outra diferença está relacionada à capacidade do tipo. Por exemplo, uma expressão envolvendo um int e um longo int resultará do tipo long int.

    Embargo!

    As conversões ocorrem da esquerda para a direita.

    Tente isto:

     int i = 3, j = 2; double k = 33; cout < < k * j / i << endl; // prints 22 cout << j / i * k << endl; // prints 0