C++ Tipos de Dados
Toda variável em C++ tem um tipo, escolhido quando ela é criada: int idade, double altura. O tipo diz que espécie de valor cabe na caixa, quanto espaço ela ocupa na memória e o que dá para fazer com ela (somar, juntar textos, perguntar se é verdade). Esta aula é o mapa: mostra os tipos que você vai usar o tempo todo, o tamanho real de cada um e como escolher. Cada família tem depois a sua própria aula.
- Os tipos do dia a dia:
int,double,char,boolestd::string. - Os "parentes":
short,long,long long,float,long double. - Como medir o tamanho de um tipo com
sizeof, e os tamanhos reais no Linux da Ana. - Como escolher o tipo certo para cada informação.
- A diferença entre tipos fundamentais (da linguagem) e tipos da biblioteca (como
std::string).
Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook, um PC comum de 64 bits), na pasta ~/cpp, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa.
A ideia: cada coisa no seu recipiente
Na cozinha, cada coisa tem o seu recipiente: ovos vão na caixa de ovos, leite vai na garrafa, açúcar vai no pote. Você até consegue pôr leite na caixa de ovos, mas vai dar errado. E ninguém guarda uma colher de sal num balde.
Os tipos do C++ são esses recipientes. Escolher o tipo é responder três perguntas:
- Que espécie de informação? Número inteiro, número com vírgula, uma letra, sim/não, um texto.
- De que tamanho? A idade de uma pessoa cabe num recipiente pequeno; a população do mundo precisa de um grande.
- Com que precisão? Um preço precisa de centavos; o número de alunos, não.
1. Os cinco tipos do dia a dia
#include <iostream>
#include <string>
int main() {
int idade = 29;
double altura = 1.65;
char inicial = 'A';
bool clienteVip = true;
std::string nome = "Ana";
std::cout << "Idade: " << idade << "\n";
std::cout << "Altura: " << altura << "\n";
std::cout << "Inicial: " << inicial << "\n";
std::cout << "VIP: " << clienteVip << "\n";
std::cout << "Nome: " << nome << "\n";
}
$ g++ -std=c++23 -Wall -Wextra tipos.cpp -o tipos $ ./tipos Idade: 29 Altura: 1.65 Inicial: A VIP: 1 « true aparece como 1 (a aula bool explica) Nome: Ana
| Tipo | Nome vem de | Guarda | Como se escreve o valor | Aula |
|---|---|---|---|---|
int | integer, "inteiro" | Números inteiros, positivos ou negativos | 29, -7, 0 | Inteiros |
double | double precision, "precisão dupla" | Números com vírgula (fração) | 1.65, -0.5, 3.0 (com ponto) | float e double |
char | character, "caractere" | Um caractere | 'A', '7', '?' (aspas simples) | Caracteres |
bool | George Boole, matemático | Verdadeiro ou falso | true, false | Booleanos |
std::string | "cadeia" (de caracteres) | Texto de qualquer tamanho | "Ana", "" (aspas duplas) | Strings |
Com esses cinco você escreve quase todos os programas do Nível 1. Os outros tipos são variações de tamanho e de precisão dos mesmos números.
Experimente: mude os valores para os seus dados e rode. Depois tente pôr "Ana" (com aspas duplas) no char inicial e leia o erro: um char guarda um caractere, entre aspas simples.
#include <iostream>
#include <string>
int main() {
std::string nome = "Ana";
int idade = 29;
double altura = 1.65;
char inicial = 'A';
bool gostaDeCafe = true;
std::cout << nome << ", " << idade << " anos, " << altura << " m, inicial "
<< inicial << ", gosta de café: " << gostaDeCafe << "\n";
}
2. Medir o tamanho: sizeof
A memória do computador é medida em bytes. Um byte é um pedacinho de memória com 8 bits (cada bit é um 0 ou 1) e consegue guardar 256 valores diferentes. Quanto mais bytes um tipo tem, maiores (ou mais precisos) os números que ele guarda.
O operador sizeof ("tamanho de") responde quantos bytes um tipo ocupa:
#include <iostream>
#include <string>
int main() {
std::cout << "bool: " << sizeof(bool) << "\n";
std::cout << "char: " << sizeof(char) << "\n";
std::cout << "short: " << sizeof(short) << "\n";
std::cout << "int: " << sizeof(int) << "\n";
std::cout << "long: " << sizeof(long) << "\n";
std::cout << "long long: " << sizeof(long long) << "\n";
std::cout << "float: " << sizeof(float) << "\n";
std::cout << "double: " << sizeof(double) << "\n";
std::cout << "long double: " << sizeof(long double) << "\n";
std::cout << "std::string: " << sizeof(std::string) << "\n";
}
$ g++ -std=c++23 -Wall -Wextra tamanhos.cpp -o tamanhos $ ./tamanhos bool: 1 char: 1 short: 2 int: 4 long: 8 long long: 8 float: 4 double: 8 long double: 16 std::string: 32
Os espaços depois dos nomes ("int: ") estão lá só para alinhar a saída em colunas.
A tabela completa
| Tipo | Bytes no Linux 64 bits (g++ 15) | Guarda | Faixa aproximada |
|---|---|---|---|
bool | 1 | verdadeiro/falso | true ou false |
char | 1 | um caractere (um número pequeno por dentro) | -128 a 127 |
short | 2 | inteiro pequeno | -32 768 a 32 767 |
int | 4 | inteiro (o padrão) | cerca de ±2,1 bilhões |
long | 8 | inteiro grande | cerca de ±9,2 quintilhões |
long long | 8 | inteiro grande (8 bytes garantidos) | cerca de ±9,2 quintilhões |
float | 4 | número com vírgula, precisão simples | uns 6 a 7 dígitos certos |
double | 8 | número com vírgula, precisão dupla (o padrão) | uns 15 a 16 dígitos certos |
long double | 16 | número com vírgula, mais precisão | uns 18 dígitos certos |
std::string | 32 | texto | (qualquer tamanho; veja abaixo) |
Os limites exatos de cada inteiro, com std::numeric_limits, estão em Inteiros; a precisão dos números com vírgula, em float e double. A referência de tipos junta tudo numa página de consulta.
A norma do C++ só garante mínimos: int tem pelo menos 2 bytes, long pelo menos 4, long long pelo menos 8. Os números acima valem para o Linux 64 bits da Ana. No Windows, por exemplo, long tem 4 bytes. No editor do guia, que roda num computador "de 32 bits" simulado (WebAssembly), long também tem 4 bytes (conferido com o Clang para esse alvo), e std::string dá outro número, porque o editor usa outra biblioteca padrão. Quando o tamanho exato importa, use long long ou os tipos de tamanho fixo, como std::int64_t (aula Inteiros).
sizeof de uma variável, e o mistério do std::string
sizeof também mede uma variável. Com variável, os parênteses são opcionais:
#include <iostream>
#include <string>
int main() {
int idade = 29;
std::string curto = "Ana";
std::string longo = "Ana Clara de Souza Albuquerque, moradora de Recife";
std::cout << sizeof(idade) << " " << sizeof idade << "\n";
std::cout << sizeof(curto) << " " << sizeof(longo) << "\n";
std::cout << curto.size() << " " << longo.size() << "\n";
}
$ g++ -std=c++23 -Wall -Wextra sizeofvar.cpp -o sizeofvar $ ./sizeofvar 4 4 32 32 « o mesmo tamanho para 3 e para 50 letras? 3 50 « .size() conta as letras de verdade
Como um texto de 50 letras cabe em 32 bytes? Não cabe. O std::string é como uma ficha de biblioteca: a ficha tem sempre o mesmo tamanho (32 bytes) e diz onde está o livro. Textos curtos cabem na própria ficha; textos longos ficam guardados em outra parte da memória, e a ficha só aponta para lá. O sizeof mede a ficha; para saber quantas letras o texto tem, use .size() (aula Funções de String).
Os valores escritos também têm tipo
Um número escrito direto no código (um literal) também tem tipo. O C++ decide pelo jeito de escrever:
$ cat literais.cpp
#include <iostream>
int main() {
std::cout << sizeof(42) << " " << sizeof(4.5) << " " << sizeof(4.5f) << " "
<< sizeof('A') << " " << sizeof(true) << "\n";
}
$ g++ -std=c++23 -Wall -Wextra literais.cpp -o literais
$ ./literais
4 8 4 1 1
| Literal | Tipo | Por quê |
|---|---|---|
42 | int | Número sem ponto. |
4.5 | double | Número com ponto. |
4.5f | float | O f no fim pede float. |
'A' | char | Aspas simples. |
true | bool | Palavra-chave de verdadeiro. |
"Ana" | texto "cru" do C (não é std::string!) | A aula auto mostra o tipo exato e o sufixo s que o transforma em std::string. |
3. Escolher o tipo certo
Na dúvida, a pergunta é "o que eu quero guardar?". Esta tabela resolve quase todos os casos:
| Quero guardar… | Use | Exemplo |
|---|---|---|
| Uma contagem, uma idade, uma quantidade, uma nota de 0 a 10 sem fração | int | int alunos = 32; |
| Um número que pode passar de 2 bilhões (população, bytes de um arquivo, milissegundos) | long long | long long habitantes = 8'100'000'000; |
| Uma medida com fração (altura, peso, média, temperatura) | double | double media = 7.75; |
| Um preço | double no começo; em sistemas de dinheiro de verdade, centavos em long long | long long precoCentavos = 1250; |
| Uma única letra ou símbolo (uma opção de menu, uma tecla) | char | char opcao = 's'; |
| Sim ou não, ligado ou desligado | bool | bool pago = false; |
| Um nome, uma frase, qualquer texto | std::string | std::string cidade = "Recife"; |
| Um número de telefone, CEP ou CPF | std::string (!) | std::string cep = "01310-100"; |
Você nunca vai somar dois telefones. E números assim têm zeros à esquerda (01310), traços e parênteses que um int jogaria fora. Regra: se você não faz contas com aquilo, guarde como texto.
O que acontece com o tipo errado
O tipo errado raramente dá erro de compilação. Na maioria das vezes, o programa roda e dá a resposta errada:
#include <iostream>
int main() {
int preco = 4.99;
int pesoKg = 2.5;
double total = preco * pesoKg;
std::cout << "Total: " << total << "\n";
}
$ g++ -std=c++23 -Wall -Wextra errado.cpp -o errado $ ./errado Total: 8 « 4 × 2: os centavos e o meio quilo sumiram
O int jogou fora a parte depois do ponto (4.99 virou 4; 2.5 virou 2), e o g++ não avisou com -Wall -Wextra. A aula Variáveis mostra como a inicialização com chaves (int preco{4.99};) transforma esse silêncio em erro.
Missão: conserte os tipos (só os tipos, sem mudar os números) para o total da feira da Ana sair certo: Total: 12.475. (No editor, o Clang ainda mostra avisos sobre a conversão: leia-os, eles apontam exatamente as linhas a consertar.)
#include <iostream>
int main() {
int preco = 4.99;
int pesoKg = 2.5;
double total = preco * pesoKg;
std::cout << "Total: " << total << "\n";
}
#include <iostream>
int main() {
double preco = 4.99;
double pesoKg = 2.5;
double total = preco * pesoKg;
std::cout << "Total: " << total << "\n";
}
4. Tipos fundamentais × tipos da biblioteca
Você deve ter reparado que quatro tipos são escritos "pelados" (int, double, char, bool) e um tem std:: na frente e pede um #include (std::string). Não é por acaso.
| Tipos fundamentais | Tipos da biblioteca padrão | |
|---|---|---|
| Exemplos | int, double, char, bool, float, long long, void | std::string, std::vector, std::array, std::map |
| De onde vêm | Fazem parte da linguagem: são palavras-chave | Foram escritos em C++ por quem fez a biblioteca, usando os fundamentais |
Precisam de #include? | Não | Sim: <string>, <vector>… |
| Prefixo | Nenhum | std:: ("standard", padrão; veja Namespaces) |
| Comparação | Os tijolos | Paredes prontas, feitas com os tijolos |
O void ("vazio") é o tipo fundamental que quer dizer "nenhum valor"; ele aparece nas funções que não devolvem nada. E a partir do Nível 2 você vai criar os seus próprios tipos, com structs e classes, do mesmo jeito que a biblioteca criou o std::string.
Esquecer o std::
#include <iostream>
#include <string>
int main() {
string nome = "Ana";
std::cout << nome << "\n";
}
$ g++ -std=c++23 -Wall -Wextra semstd.cpp -o semstd
semstd.cpp: In function ‘int main()’:
semstd.cpp:5:5: error: ‘string’ was not declared in this scope
5 | string nome = "Ana";
| ^~~~~~
semstd.cpp:5:5: note: suggested alternatives:
In file included from /usr/include/c++/15/iosfwd:43,
from /usr/include/c++/15/ios:42,
from /usr/include/c++/15/bits/ostream.h:43,
from /usr/include/c++/15/ostream:42,
from /usr/include/c++/15/iostream:43,
from semstd.cpp:1:
/usr/include/c++/15/bits/stringfwd.h:79:33: note: ‘std::string’
79 | typedef basic_string<char> string;
| ^~~~~~
In file included from /usr/include/c++/15/ostream:44:
/usr/include/c++/15/format:5121:5: note: ‘std::range_format::string’
5121 | string,
| ^~~~~~
In file included from /usr/include/c++/15/bits/locale_classes.h:42,
from /usr/include/c++/15/bits/ios_base.h:43,
from /usr/include/c++/15/ios:46:
/usr/include/c++/15/string:80:11: note: ‘std::pmr::string’
80 | using string = basic_string<char>;
| ^~~~~~
semstd.cpp:6:18: error: ‘nome’ was not declared in this scope
6 | std::cout << nome << "\n";
| ^~~~
A mensagem é longa, mas só duas linhas importam:
error: ‘string’ was not declared in this scope: sem ostd::, o compilador não acha o nomestring.note: ‘std::string’: entre as "alternativas sugeridas" (suggested alternatives), a primeira é a certa. As linhasIn file included from…só mostram onde, dentro da biblioteca, ele encontrou cada sugestão; pode pular.- O segundo erro (
‘nome’ was not declared) é consequência do primeiro: como a declaração falhou,nomenão existe. Conserte o primeiro erro e ele some.
#include <string>?
No laboratório, um programa com std::string e só #include <iostream> compilou e rodou, no g++ e no Clang, porque o <iostream> da biblioteca de hoje já traz o <string> junto, "de carona". Mas a norma não garante essa carona, e outra versão do compilador pode recusar o mesmo arquivo. Regra do guia: usou, inclua.
Quando dá errado
O que significa: um valor com vírgula foi parar numa variável inteira (int, long…), e a fração foi jogada fora.
Como consertar: use double para medidas e preços. Inicialize com chaves ({ }) para o compilador barrar esse corte.
error: ‘string’ was not declared in this scope
O que significa: faltou o std:: (ou o #include <string>).
Como consertar: escreva std::string e confira o #include <string> no topo.
error: invalid conversion from ‘const char*’ to ‘char’ (ou to ‘int’)
O que significa: um texto entre aspas duplas foi posto numa variável que não é de texto.
Como consertar: para texto, std::string. Para um único caractere, char com aspas simples: 'A'. A diferença é explicada em Caracteres.
sizeof deu um número diferente do da tabela
O que significa: você está em outro sistema (Windows, 32 bits, o editor do guia em WebAssembly). Os tamanhos dependem da plataforma.
Como consertar: nada a consertar. Se o seu programa depende de um tamanho exato, use long long ou os tipos de <cstdint>, como std::int32_t (aula Inteiros).
Referência rápida
| Escrita | O que faz |
|---|---|
int x = 29; | Inteiro |
long long x = 8'100'000'000; | Inteiro grande (8 bytes) |
double x = 1.65; | Número com vírgula (o padrão) |
float x = 1.65f; | Número com vírgula, menos preciso |
char c = 'A'; | Um caractere (aspas simples) |
bool b = true; | Verdadeiro ou falso |
std::string s = "Ana"; | Texto (precisa de #include <string>) |
sizeof(tipo) / sizeof variavel | Quantos bytes ocupa |
texto.size() | Quantos caracteres um std::string tem |
Exercícios
1. O tipo da média
A média de um aluno pode ser 7.75. Complete com o tipo certo:
2. Quantos bytes?
No Linux 64 bits da Ana, sizeof(int) mostra:
3. Qual é o melhor tipo para guardar um CEP como 01310-100?
4. Um std::string com 3 letras e outro com 50 letras. O que sizeof mostra para cada um (g++ 15, Linux 64 bits)?
5. Qual destes é um tipo da biblioteca, e não da linguagem?
Missão final: a ficha do cliente
Missão: crie cinco variáveis, cada uma com o tipo certo: o nome Bruno, a idade 31, a altura 1.78, a inicial B e se ele é estudante (não é: false). Mostre a ficha exatamente assim (o false aparece como 0):
Nome: Bruno Idade: 31 Altura: 1.78 Inicial: B Estudante: 0
#include <iostream>
#include <string>
int main() {
// crie as cinco variáveis aqui
// mostre a ficha aqui
}
#include <iostream>
#include <string>
int main() {
std::string nome = "Bruno";
int idade = 31;
double altura = 1.78;
char inicial = 'B';
bool estudante = false;
std::cout << "Nome: " << nome << "\n";
std::cout << "Idade: " << idade << "\n";
std::cout << "Altura: " << altura << "\n";
std::cout << "Inicial: " << inicial << "\n";
std::cout << "Estudante: " << estudante << "\n";
}
Resumo
- O tipo diz que valor cabe na variável, quanto espaço ela ocupa e o que dá para fazer com ela.
- Os cinco do dia a dia:
int(inteiro),double(com vírgula),char(um caractere,'A'),bool(true/false) estd::string(texto,"Ana"). sizeofmede bytes. No Linux 64 bits:bool/char1,short2,int/float4,long/long long/double8,long double16,std::string32. Outros sistemas podem diferir.- Escolha pelo que você guarda: contagem →
int; medida →double; sim/não →bool; texto (inclusive telefone e CEP) →std::string. - Tipo errado quase sempre compila e dá resposta errada.
- Fundamentais (
int,double…) são da linguagem; os da biblioteca (std::string,std::vector) pedem#includeestd::.