C++ Conversão de Tipos

Em C++, todo valor tem um tipo: 7 é um int, 9.99 é um double, 'A' é um char. Muitas vezes você precisa usar um valor de um tipo onde se espera outro: guardar um preço com centavos numa variável de números inteiros, calcular a média de notas inteiras com vírgula, descobrir o código de uma letra. Essa passagem de um tipo para outro se chama conversão. Às vezes o C++ a faz sozinho, sem avisar nada; às vezes você precisa pedir. Nesta aula você vai ver as duas formas e as armadilhas de cada uma.

Você vai aprender
  • O que é conversão implícita (automática): int → double não perde nada; double → int corta a parte depois do ponto.
  • Como pedir ao g++ que avise dessas perdas com -Wconversion.
  • Como converter de propósito com static_cast<T>(valor).
  • Por que 7 / 2 dá 3, e como obter 3.5.
  • O que é o cast "estilo C" (int)x e por que preferir static_cast.
  • Como passar de char para int e de volta.

Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cpp, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa (veja Compilar com g++). Você pode repetir cada um no editor do guia, que compila C++ de verdade no navegador.


A ideia: passar água de um copo para outro

Imagine dois recipientes na cozinha da Ana: uma jarra grande, com marcações de meio em meio copo, e uma forminha de gelo, em que cada buraco guarda uma porção inteira, sem frações.

  • Passar da forminha para a jarra é tranquilo: 7 porções inteiras viram "7,0" na jarra. Nada se perde.
  • Passar da jarra para a forminha é diferente: se a jarra tem "9,99", só cabem 9 porções inteiras. O "0,99" que sobrou vai para a pia. Ninguém arredonda para 10.

No C++, o int é a forminha (só números inteiros, veja Inteiros) e o double é a jarra (números com parte fracionária, veja float e double). Toda conversão é uma dessas duas situações: ou o valor cabe no tipo novo, ou alguma coisa se perde.


1. Conversão implícita: o C++ converte sozinho

"Implícita" quer dizer "sem ninguém pedir". Sempre que você coloca um valor de um tipo numa variável de outro tipo, o C++ tenta converter automaticamente. Veja os dois sentidos no mesmo programa:

#include <iostream>

int main() {
    int caixas = 7;
    double total = caixas;      // int vira double
    std::cout << total << '\n';
    std::cout << total / 2 << '\n';

    double preco = 9.99;
    int reais = preco;          // double vira int: corta
    std::cout << reais << '\n';

    double temperatura = -2.7;
    int t = temperatura;
    std::cout << t << '\n';
}
double total = caixas;
O lado direito é um int (7). A variável é double. O C++ converte o 7 em 7.0 e guarda. Isso se chama conversão de alargamento: o tipo novo é "maior", tudo cabe.
total / 2
Como total é double, a divisão é feita com vírgula: 7.0 / 2 = 3.5.
int reais = preco;
O lado direito é double (9.99); a variável é int. O C++ joga fora tudo depois do ponto. Isso é uma conversão de estreitamento (em inglês, narrowing): o tipo novo é "menor".
int t = temperatura;
Com números negativos, o corte também vai em direção ao zero: −2.7 vira −2 (e não −3).
$ g++ -std=c++23 -Wall -Wextra implicita.cpp -o implicita
$ ./implicita
7          « o double 7.0 aparece sem o ".0": o cout esconde zeros que não mudam o valor
3.5
9          « 9.99 virou 9: os 99 centavos foram para a pia
-2         « -2.7 virou -2: corta em direção ao zero

Repare no detalhe mais importante: o g++ compilou sem nenhum aviso, mesmo com -Wall -Wextra. Para ele, cortar 9.99 em 9 é uma operação legal, que você pode ter feito de propósito. Os 99 centavos sumiram em silêncio.

Cortar não é arredondar

A conversão de double para int sempre corta (os matemáticos dizem "trunca"): 9.99 vira 9, 9.5 vira 9, 9.01 vira 9. Se você quer arredondar, use std::round, mostrado mais abaixo nesta aula.

Pedindo o aviso: -Wconversion

O g++ tem uma opção que não faz parte do -Wall nem do -Wextra: -Wconversion ("avisar sobre conversões"). Com ela, toda conversão que pode mudar o valor vira um aviso. É o mesmo programa, compilado de novo com a opção a mais:

$ g++ -std=c++23 -Wall -Wextra -Wconversion implicita.cpp -o implicita
implicita.cpp: In function ‘int main()’:
implicita.cpp:10:17: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
   10 |     int reais = preco;          // double vira int: corta
      |                 ^~~~~
implicita.cpp:14:13: warning: conversion from ‘double’ to ‘int’ may change value [-Wfloat-conversion]
   14 |     int t = temperatura;
      |             ^~~~~~~~~~~

Leia o aviso por partes (a aula Lendo Erros do Compilador explica o formato):

PedaçoO que quer dizer
implicita.cpp:10:17Arquivo, linha 10, coluna 17: onde está o problema.
warning:É um aviso, não um erro: o programa foi gerado mesmo assim.
conversion from ‘double’ to ‘int’ may change value"A conversão de double para int pode mudar o valor."
[-Wfloat-conversion]O nome do tipo de aviso. -Wfloat-conversion (conversões com números de ponto flutuante) é uma parte do -Wconversion.

Repare que a linha 5 (double total = caixas;) não foi avisada: de int para double o valor nunca muda. O aviso aparece só onde pode haver perda.

Vale a pena ligar?

Em programas pequenos, como os deste guia, sim: -Wconversion pega exatamente o tipo de engano que esta aula ensina. Em projetos grandes ele pode avisar demais, e muita gente liga só em partes do código. A aula Avisos (-Wall -Wextra) mostra outras opções úteis. O comando padrão do guia continua sendo -Wall -Wextra; quando usarmos -Wconversion, ele vai aparecer escrito.

Outros estreitamentos silenciosos

Não é só a parte fracionária que se perde. Um número grande demais para o tipo novo também é "estragado" em silêncio:

#include <iostream>

int main() {
    long long populacao = 5000000000;
    int p = populacao;
    std::cout << p << '\n';
    int negativo = -1;
    unsigned int u = negativo;
    std::cout << u << '\n';
}
$ g++ -std=c++23 -Wall -Wextra grande.cpp -o grande
$ ./grande
705032704        « cinco bilhões não cabem num int: sobrou um número sem sentido
4294967295       « -1 num unsigned (sem sinal) vira o maior unsigned int
$ g++ -std=c++23 -Wall -Wextra -Wconversion grande.cpp -o grande
grande.cpp: In function ‘int main()’:
grande.cpp:5:13: warning: conversion from ‘long long int’ to ‘int’ may change value [-Wconversion]
    5 |     int p = populacao;
      |             ^~~~~~~~~

Um int vai só até 2.147.483.647 (veja Inteiros). O que passa disso "dá a volta" e vira outro número. Já o −1 dentro de um unsigned int (um inteiro que não tem sinal, só aceita 0 e positivos) vira 4294967295. Esse comportamento volta a aparecer, de forma bem mais traiçoeira, na aula Operadores de Comparação. O aviso de int para unsigned tem nome próprio, -Wsign-conversion, e não vem nem com o -Wconversion.

As chaves pegam o estreitamento

Na aula Variáveis você viu que dá para inicializar com chaves: int x{5};. Uma das vantagens das chaves é exatamente esta: elas não aceitam estreitamento.

#include <iostream>

int main() {
    double preco = 9.99;
    int reais{preco};
    std::cout << reais << '\n';
}
$ g++ -std=c++23 -Wall -Wextra estreita.cpp -o estreita
estreita.cpp: In function ‘int main()’:
estreita.cpp:5:15: warning: narrowing conversion of ‘preco’ from ‘double’ to ‘int’ [-Wnarrowing]
    5 |     int reais{preco};
      |               ^~~~~

"Conversão de estreitamento de preco, de double para int." Aqui o g++ dá só um aviso, sem precisar de -Wconversion. Se o valor for escrito direto, como int reais{9.99};, o g++ recusa de vez:

$ g++ -std=c++23 -Wall -Wextra estreita2.cpp -o estreita2
estreita2.cpp: In function ‘int main()’:
estreita2.cpp:4:15: error: narrowing conversion of ‘9.9900000000000002e+0’ from ‘double’ to ‘int’ [-Wnarrowing]
    4 |     int reais{9.99};
      |               ^~~~

(O 9.9900000000000002e+0 é o 9.99 do jeito que ele fica guardado na memória: double quase nunca guarda o número exato. A aula float e double explica.) No editor do guia, que usa o Clang, os dois casos são erro: type 'double' cannot be narrowed to 'int' in initializer list.

Experimente: rode o programa e veja os cortes. Depois troque 8.75 por 8.999 e por -8.999. Por fim, troque int a = nota; por int a{nota}; e veja o compilador recusar.

#include <iostream>

int main() {
    double nota = 8.75;
    int a = nota;
    std::cout << "nota (double): " << nota << '\n';
    std::cout << "a (int):       " << a << '\n';
}

2. Conversão explícita com static_cast

Quando a conversão é de propósito, diga isso no código. A ferramenta do C++ para isso é o static_cast ("conversão estática", ou seja, decidida na hora de compilar). Uma conversão pedida por você se chama explícita, ou um cast (em inglês, "moldar": você coloca o valor num molde de outro tipo).

#include <iostream>

int main() {
    double preco = 9.99;
    int a = static_cast<int>(preco);   // C++: o jeito recomendado
    int b = (int)preco;                // estilo C
    int c = int(preco);                // estilo "função"
    std::cout << a << ' ' << b << ' ' << c << '\n';
}
static_cast
A palavra que pede a conversão. É uma palavra reservada do C++, não precisa de #include.
<int>
Entre os sinais de menor e maior, o tipo de destino: "converta para int".
(preco)
Entre parênteses, o valor que será convertido. Pode ser uma variável, um número ou uma conta inteira: static_cast<int>(preco * 100).
(int)preco e int(preco)
Outras duas formas de escrever a mesma conversão. Você vai entender a diferença na seção 4.
$ g++ -std=c++23 -Wall -Wextra -Wconversion cast.cpp -o cast
$ ./cast
9 9 9

O resultado é o mesmo corte (9), mas agora nem com -Wconversion aparece aviso. É como assinar embaixo: "eu sei que vou perder os centavos e é isso que eu quero". Quem lê o código também entende na hora que a perda foi de propósito.

E se eu quiser arredondar?

O static_cast só corta. Para arredondar, use std::round da biblioteca <cmath> (a aula Matemática (cmath) mostra todas as funções). Ele arredonda para o inteiro mais próximo e devolve um double; se você precisar de um int, converta o resultado:

#include <cmath>
#include <iostream>

int main() {
    double preco = 9.99;
    std::cout << static_cast<int>(preco) << '\n';
    std::cout << std::round(preco) << '\n';
    std::cout << static_cast<int>(std::round(preco)) << '\n';
    std::cout << std::lround(-2.7) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra arredondar.cpp -o arredondar
$ ./arredondar
9        « static_cast: corta
10       « std::round: arredonda (resultado double)
10       « arredonda e depois converte para int
-3       « std::lround arredonda e já devolve um inteiro (long)

3. Divisão inteira × divisão real

Esta é a conversão que mais engana quem começa. Em C++, o tipo do resultado de uma conta depende do tipo dos números da conta, e não da variável onde você vai guardar o resultado.

  • Se os dois lados da divisão são int, a divisão é inteira: o resultado é um int, e a parte fracionária é cortada.
  • Se pelo menos um lado é double, o outro é convertido para double automaticamente (é uma conversão implícita), e a divisão é real.
#include <iostream>

int main() {
    std::cout << 7 / 2 << '\n';
    std::cout << 7 / 2.0 << '\n';
    std::cout << 7.0 / 2 << '\n';
    std::cout << static_cast<double>(7) / 2 << '\n';
    std::cout << static_cast<double>(7 / 2) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra divisao.cpp -o divisao
$ ./divisao
3
3.5
3.5
3.5
3
ExpressãoTiposResultadoPor quê
7 / 2int / int3Divisão inteira: 3,5 é cortado para 3.
7 / 2.0int / double3.5O 2.0 é double, então o 7 vira 7.0.
7.0 / 2double / int3.5Basta um dos lados ser double.
static_cast<double>(7) / 2double / int3.5O cast transforma o 7 em 7.0 antes da divisão.
static_cast<double>(7 / 2)double( int / int )3Armadilha: os parênteses fazem a divisão inteira primeiro (dá 3), e só depois o 3 vira 3.0. Tarde demais.

Com números escritos direto no código, basta colocar .0. Mas com variáveis int não dá para "colocar .0": é aí que o static_cast é indispensável. O caso clássico é a média de notas:

#include <iostream>

int main() {
    int soma = 17;     // 8 + 9
    int provas = 2;
    double media_errada = soma / provas;
    double media = static_cast<double>(soma) / provas;
    std::cout << "Errada: " << media_errada << '\n';
    std::cout << "Certa: " << media << '\n';
}
$ g++ -std=c++23 -Wall -Wextra media.cpp -o media
$ ./media
Errada: 8
Certa: 8.5
  1. soma / provas: os dois são int, então a conta é inteira: 17 / 2 = 8 (o 0,5 se perde aqui).
  2. double media_errada = 8;: o 8 vira 8.0, mas a metade já foi embora no passo anterior. A variável ser double não ajuda.
  3. static_cast<double>(soma): o 17 vira 17.0 antes da divisão.
  4. 17.0 / provas: um lado é double, então o 2 vira 2.0 e a conta é real: 8.5.

O g++ não avisa nada, nem com -Wconversion, porque nenhuma conversão perdeu valor: quem "perdeu" foi a divisão inteira, que é uma operação legítima. A aula Operadores Aritméticos mostra a divisão inteira com mais detalhes, incluindo o resto (%).

Missão: o programa calcula a média de 4 notas, mas mostra Média: 7. Corrija a linha da média com static_cast<double> para aparecer Média: 7.5.

#include <iostream>

int main() {
    int n1 = 7;
    int n2 = 8;
    int n3 = 6;
    int n4 = 9;
    int soma = n1 + n2 + n3 + n4;
    double media = soma / 4;
    std::cout << "Média: " << media << '\n';
}
#include <iostream>

int main() {
    int n1 = 7;
    int n2 = 8;
    int n3 = 6;
    int n4 = 9;
    int soma = n1 + n2 + n3 + n4;
    double media = static_cast<double>(soma) / 4;
    std::cout << "Média: " << media << '\n';
}

4. O cast estilo C: (int)x

O C++ nasceu do C (veja O que é C++), e o C tem uma forma curta de converter: o tipo entre parênteses antes do valor, (int)preco. O C++ aceita, e também aceita a forma int(preco), que parece uma função. Você vai ver as duas em código antigo e na internet. No programa cast.cpp acima, as três formas deram 9.

Então qual é o problema? O cast estilo C é poderoso demais. O static_cast só faz conversões que fazem sentido (número para número, por exemplo) e recusa as absurdas. O cast estilo C tenta todas as conversões possíveis, inclusive as perigosas, até achar uma que funcione. Compare os dois tentando transformar o texto "29" em número:

$ cat texto2.cpp
#include <iostream>

int main() {
    int idade = static_cast<int>("29");
    std::cout << idade << '\n';
}
$ g++ -std=c++23 -Wall -Wextra texto2.cpp -o texto2
texto2.cpp: In function ‘int main()’:
texto2.cpp:4:17: error: invalid ‘static_cast’ from type ‘const char [3]’ to type ‘int’
    4 |     int idade = static_cast<int>("29");
      |                 ^~~~~~~~~~~~~~~~~~~~~~

O static_cast recusou: "static_cast inválido do tipo const char [3] (um texto de 3 caracteres: 2, 9 e o terminador) para o tipo int". Ótimo: o erro aparece na hora de compilar. Agora o mesmo pedido com o cast estilo C (usando long, um inteiro maior):

$ cat perigo.cpp
#include <iostream>

int main() {
    long idade = (long)"29";
    std::cout << idade << '\n';
}
$ g++ -std=c++23 -Wall -Wextra perigo.cpp -o perigo
$ ./perigo
104665125543940       « não é 29!
$ ./perigo
97150230274052        « e muda a cada execução

Compilou sem nenhum aviso e mostrou um número enorme, diferente a cada vez. Esse número é o endereço na memória onde o texto "29" está guardado (você vai entender endereços na aula Ponteiros). O cast estilo C fez uma conversão que não tem nada a ver com "texto para número", e ficou quieto. Esse é o motivo de preferir static_cast: ele é mais fácil de achar no código (procure por _cast) e recusa o que não faz sentido.

Se você quiser que o g++ aponte os casts estilo C no seu código, existe o aviso -Wold-style-cast ("cast à moda antiga"). Ele até sugere a troca:

$ g++ -std=c++23 -Wall -Wextra -Wold-style-cast cast.cpp -o cast
cast.cpp: In function ‘int main()’:
cast.cpp:6:18: warning: use of old-style cast to ‘int’ [-Wold-style-cast]
    6 |     int b = (int)preco;                // estilo C
      |                  ^~~~~
      |             ----------
      |             static_cast<int> (preco)
Existem outros _cast

O C++ tem mais três: const_cast, reinterpret_cast e dynamic_cast. Eles servem para situações bem específicas com ponteiros e classes, que aparecem nos níveis 2 e 3 (por exemplo, Polimorfismo). No dia a dia, com números, só o static_cast interessa.


5. char ↔ int: letras são números

Na aula Caracteres (char) você viu que um char guarda um número: o código da letra na tabela ASCII. O 'A' é 65, o 'B' é 66, o 'a' é 97, e o caractere '0' é 48 (não zero!). Por isso, converter entre char e int é natural:

#include <iostream>

int main() {
    char letra = 'A';
    int codigo = letra;                       // char vira int
    std::cout << codigo << '\n';
    std::cout << letra + 1 << '\n';           // a conta é feita em int
    std::cout << static_cast<char>(letra + 1) << '\n';

    char digito = '7';
    int valor = digito - '0';                 // '7' (55) - '0' (48)
    std::cout << valor << '\n';
    std::cout << static_cast<int>(digito) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra letras.cpp -o letras
$ ./letras
65       « o código do 'A'
66       « 'A' + 1: o char virou int para a conta, e o cout mostra o número
B        « convertendo 66 de volta para char, o cout mostra a letra
7        « '7' - '0' = 55 - 48 = 7: o algarismo como número
55       « o código do caractere '7'
int codigo = letra;
Conversão implícita de alargamento: todo char cabe num int.
letra + 1
Em contas, o C++ converte o char para int antes de calcular (isso se chama promoção). O resultado é int, e o cout mostra int como número.
static_cast<char>(letra + 1)
Para ver a letra, converta de volta para char. O cout decide como mostrar pelo tipo: char aparece como letra, int como número.
digito - '0'
Os algarismos '0' a '9' ficam em sequência na tabela (48 a 57). Subtrair '0' dá o valor do algarismo. Esse truque é muito usado para ler números caractere por caractere.
Só funciona com um caractere

digito - '0' converte um algarismo. Para converter um texto inteiro, como "2026", para número, existem funções próprias (std::stoi e companhia), assunto da aula Texto ↔ Número. E letras com acento ('é', 'ç') não cabem num único char: veja Acentos e UTF-8.

bool ↔ int

O bool (veja Booleanos) também conversa com números: true vira 1 e false vira 0; no sentido contrário, zero vira false e qualquer outro número vira true.

#include <iostream>

int main() {
    bool ligado = true;
    int n = ligado;
    std::cout << n << '\n';

    int pontos = 5;
    bool tem_pontos = pontos;
    std::cout << tem_pontos << '\n';

    bool vazio = 0;
    std::cout << vazio << '\n';
}
$ g++ -std=c++23 -Wall -Wextra booleano.cpp -o booleano
$ ./booleano
1        « true vira 1
1        « 5 é diferente de zero: vira true, que o cout mostra como 1
0        « 0 vira false

Experimente: troque a letra 'C' por outras ('a', 'Z', '!') e veja o código de cada uma. Depois mude o + 2 para andar mais letras.

#include <iostream>

int main() {
    char letra = 'C';
    std::cout << "Letra: " << letra << '\n';
    std::cout << "Código: " << static_cast<int>(letra) << '\n';
    std::cout << "Duas letras depois: " << static_cast<char>(letra + 2) << '\n';
}

6. Texto não é número (e cast não resolve)

Um engano comum: achar que "29" (entre aspas) e 29 são a mesma coisa. Não são. "29" é um texto com os caracteres 2 e 9. Nenhum cast transforma texto em número:

$ cat texto.cpp
#include <iostream>

int main() {
    int idade = "29";
    std::cout << idade << '\n';
}
$ g++ -std=c++23 -Wall -Wextra texto.cpp -o texto
texto.cpp: In function ‘int main()’:
texto.cpp:4:17: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
    4 |     int idade = "29";
      |                 ^~~~
      |                 |
      |                 const char*

"Conversão inválida de const char* para int." Para o C++, um texto entre aspas vira um const char*, o endereço de memória onde o texto começa (a setinha embaixo mostra esse tipo). O [-fpermissive] no fim diz que existe uma opção para o g++ "deixar passar", mas não use: o resultado seria o endereço de memória, como no perigo.cpp. Para converter texto em número de verdade, veja Texto ↔ Número.


Formas diferentes: qual usar

FormaExemploQuando usar
Implícita, sem perdadouble d = 7;À vontade: int → double, char → int nunca perdem nada.
Implícita, com perdaint r = 9.99;Evite: a perda fica escondida. Ligue -Wconversion para achar esses lugares.
Inicialização com chavesint r{9.99};Use chaves para o compilador recusar estreitamentos sem querer.
static_caststatic_cast<int>(9.99)Sempre que a conversão é de propósito. É o padrão deste guia.
Cast estilo C(int)9.99Só para entender código antigo. Não escreva código novo assim.
Estilo funçãoint(9.99)Igual ao estilo C em poder. Também evite.
std::round / std::lroundstd::lround(9.99)Quando você quer arredondar, não cortar.

Quando dá errado

A média deu 8, mas deveria dar 8.5
$ ./media
Errada: 8          « a média sem static_cast
Certa: 8.5

O que aconteceu: a divisão soma / provas foi feita entre dois int, então foi inteira. Guardar o resultado num double não recupera o que já foi cortado. Nenhum compilador avisa, porque a divisão inteira é uma operação válida.

Como resolver: converta um dos lados antes da divisão: static_cast<double>(soma) / provas. Cuidado para não escrever static_cast<double>(soma / provas), que converte depois.

error: invalid conversion from ‘const char*’ to ‘int’

O que aconteceu: você tentou guardar um texto entre aspas ("29") numa variável numérica.

Como resolver: se o valor é fixo, tire as aspas: int idade = 29;. Se o texto vem de fora (do teclado, de um arquivo), use std::stoi, da aula Texto ↔ Número. Não "resolva" com (int) ou (long): compila, mas o valor é um endereço de memória.

error: narrowing conversion of … from ‘double’ to ‘int’

O que aconteceu: você inicializou com chaves (int x{9.99};) um valor que não cabe no tipo sem perder parte dele. As chaves foram feitas justamente para impedir isso.

Como resolver: decida o que você quer. Se a variável deveria guardar a parte fracionária, troque o tipo para double. Se você quer mesmo cortar, diga isso: int x{static_cast<int>(9.99)};.

Um número enorme virou outro sem sentido (705032704)

O que aconteceu: um valor de um tipo maior (long long) foi colocado num tipo menor (int), e não coube. O g++ só avisa com -Wconversion.

Como resolver: use um tipo que comporte o valor (long long, veja Inteiros) e compile com -Wconversion para achar outros pontos parecidos.


Referência

De → paraAutomático?O que aconteceExemplo
int → doubleSimGanha .0, nada se perde.7 → 7.0
double → intSim, em silêncioCorta em direção ao zero.9.99 → 9, -2.7 → -2
long long → intSim, em silêncioSe não couber, vira outro número.5000000000 → 705032704
int → unsignedSim, em silêncioNegativos viram números enormes.-1 → 4294967295
char → intSimDá o código da tabela ASCII.'A' → 65
int → charSimDá o caractere daquele código.66 → 'B'
bool → intSimtrue → 1, false → 0.
número → boolSim0 → false; qualquer outro → true.5 → true
texto → númeroNãoErro de compilação. Use std::stoi.Texto ↔ Número
Opção do g++O que avisa
-WconversionConversões implícitas que podem mudar o valor (inclui -Wfloat-conversion).
-Wsign-conversionConversões entre tipos com e sem sinal.
-Wold-style-castCasts estilo C, (int)x.
-WnarrowingEstreitamento dentro de chaves (já vem ligado).

Exercícios

1. Converta de propósito

Complete para guardar em inteiro só a parte inteira de altura, do jeito recomendado pelo C++:

int inteiro =

2. Divisão real

total e pessoas são int. Complete para a divisão ser real (com vírgula), convertendo o total:

double cada = / pessoas;

3. Do algarismo ao número

A variável c guarda o caractere '4'. Complete para n valer o número 4:

int n = c - ;

4. O que std::cout << static_cast<double>(9 / 2); mostra?

5. int x = -7.9; — quanto vale x?

6. Por que preferir static_cast<int>(x) a (int)x?

Missão final: a conta do restaurante

Missão: a conta deu 183 reais, inteiros, para 4 pessoas. Calcule quanto cada um paga, com centavos, usando static_cast<double>. Depois mostre quantas notas de 1 real inteiras isso dá, usando static_cast<int> no valor de cada um. A saída deve ser:

Cada um paga: 45.75
Em notas de 1 real: 45
#include <iostream>

int main() {
    int conta = 183;
    int pessoas = 4;
    // calcule "cada" (double) e "notas" (int) aqui

}
#include <iostream>

int main() {
    int conta = 183;
    int pessoas = 4;
    double cada = static_cast<double>(conta) / pessoas;
    int notas = static_cast<int>(cada);
    std::cout << "Cada um paga: " << cada << '\n';
    std::cout << "Em notas de 1 real: " << notas << '\n';
}

Resumo

  • Conversão implícita: o C++ converte sozinho. int → double não perde nada; double → int corta em direção ao zero, sem aviso.
  • -Wconversion faz o g++ avisar das conversões que podem mudar o valor. Inicializar com chaves (int x{…}) recusa o estreitamento.
  • Conversão explícita: static_cast<tipo>(valor). Use sempre que a conversão for de propósito.
  • int / int é divisão inteira (7 / 2 = 3). Para ter 3.5, um dos lados precisa ser double antes da conta: 7 / 2.0 ou static_cast<double>(a) / b.
  • Cortar não é arredondar: para arredondar, std::round / std::lround.
  • O cast estilo C (int)x existe, mas aceita conversões absurdas em silêncio. Prefira static_cast.
  • char é um número: 'A' é 65; '7' - '0' é 7; static_cast<char>(66) é 'B'.
  • Texto ("29") não vira número com cast: veja Texto ↔ Número.