Tipos de Dados em C++
Introdução ao Tipos de Dados em C++
Por Fábio dos Reis
A linguagem C++ é uma linguagem fortemente tipada. Isso significa que cada variável no programa possui um tipo associado a ela, que define o que ela pode armazenar. O compilador realiza verificação rígida dos tipos ao compilar um programa em C++ para assegurar que o tipo correto esteja sendo usado e que os tipos sejam compatíveis quando combinados entre si (por exemplo, em cálculos).
Existem sete tipos de dados básicos ou fundamentais em C++, chamados de Tipos Primitivos. A tabela a seguir mostra os tipos básicos primitivos em C++, com a palavra-chave usada em sua declaração e o tamanho em bytes ocupado por cada elemento do tipo na memória RAM:
Tipo | Descrição | Faixa de valores | Tamanho (bytes) |
int | Inteiro | -2.147.483.648 a -2.147.483.647 | 2 ou 4 |
float | Ponto Flutuante, 7 dígitos de precisão | -3,4 x 1038 a 3,4 x 1038 | 4 |
double | Ponto Flutuante Duplo, 15 dígitos de precisão | -1,7 x 10308 a 1,7 x 10308 | 8 |
char | Caractere | caracteres | 1 |
wchar_t | Caractere Ampliado | – | – |
bool | Lógico | true | false | 1 |
void | Sem Valor (usado em funções que não retornam valores) | – | – |
Os tipos numéricos ou aritméticos que usamos em C++ são divididos em duas grandes categorias: tipos inteiros (números inteiros) e tipos de ponto flutuante (números fracionários). Existem diversos tipos de dados em cada uma dessas categorias, cada um com uma faixa de valores permitida (quantidade de valores possíveis) que o tipo pode armazenar.
Modificadores de Tipo
Um modificador é uma palavra-chave acrescentada ao nome de um tipo em sua declaração, que permite modificar seu comportamento de duas formas:
- Estendendo a faixa de valores suportada pelo tipo
- Permitindo ou não o emprego de números negativos (com sinal).
Alguns dos tipos básicos podem ser estendidos usando os seguintes modificadores e suas combinações:
- Long
- Short
- Unsigned
- Signed
Basicamente, esses modificadores expandem os valores mínimo e máximo da faixa de valores de cada tipo e determinam se os valores podem ser negativos ou somente positivos.
Tipos com sinal – signed
Um tipo com sinal (“signed”) é um tipo que permite a representação de valores positivos e negativos. É empregado quando precisamos armazenar valores negativos em um programa.
Um exemplo é o armazenamento de temperaturas – podemos armazenar tanto valores positivos como +32°C (temperatura real no momento em que escrevo esse artigo!) quanto temperaturas negativas como -15°C.
Por exemplo, o tipo int permite a faixa de valores de –2.147.483.648 a +2.147.483.647. A tabela a seguir mostra os tipos inteiros disponíveis em C++ incluindo a aplicação dos modificadores:
Tipo | Faixa de Valores | Tamanho em bytes (típico) |
char |
-128 a +127 | 1 |
short |
-32768 a +32767 | 2 |
int |
-2.147.483.648 a +2.147.483.647 | 4 |
long long int signed long signed long int |
igual a int ou long long (depende da implementação) |
4 ou 8 |
(a partir do C++11) long long long long int signed long long signed long long int |
-9223372036854775808 a +9223372036854775807 | 8 |
Na tabela acima, temos os nomes de tipos na coluna à esquerda e, como podemos ver, alguns nomes são compostos por mais de uma palavra. Sempre que possível usamos o nome mais curto disponível para o tipo em questão.
Assim, é muito comum usar, por exemplo, “long” do que “signed long int”, que representa o mesmo tipo (porém de forma mais explícita e melhor documentada).
O modificador signed para números inteiros é, na verdade, opcional. Se for omitido, o valor terá sinal por padrão.
Tipos sem sinal – unsigned
Já um tipo sem sinal (“unsigned”) somente permite a representação de números positivos, no mesmo espaço de armazenamento, tendo portanto uma faixa de valores positivos estendida. É usado, como podemos imaginar, quando não há a necessidade de armazenar números negativos no programa.
Um exemplo é o armazenamento da idade de uma pessoa – as idades são sempre números positivos; você pode ter 30 anos de idade, mas nunca -30 anos!
A tabela a seguir mostra os tipos inteiros em C++ sem sinal:
Tipo | Faixa de Valores | Tamanho em bytes (típico) |
unsigned char | 0 a 255 | 1 |
unsigned short | 0 a 65535 | 2 |
unsigned int | 0 a 4294967295 | 4 |
unsigned long unsigned long int |
igual a unsigned int ou unsigned long long (depende da implementação) |
4 ou 8 |
unsigned long long unsigned long long int |
0 a 18446744073709551615 | 8 |
Para criar um tipo sem sinal devemos obrigatoriamente usar a palavra-chave unsigned antes do nome do tipo em si, como no exemplo a seguir:
unsigned short int // Tipo inteiro curto sem sinal
Números de Ponto Flutuante
Números de ponto flutuante permitem representar valores fracionários, positivos e negativos, como 3.1415 ou -9.345464576, além de permitirem o armazenamento de valores muito grandes (ou muito pequenos), em faixas de valores bem maiores que as possíveis com números inteiros.
Um número de ponto flutuante normalizado consiste em duas partes: uma mantissa e um expoente. A magnitude de um número é o valor da mantissa multiplicado por 10 elevado à potência do expoente.
Por exemplo, o número de dias em um ano típico, 365, pode ser escrito como um valor de ponto flutuante de precisão fixa em notação E (exponencial / científica) da seguinte forma:
3.650000E02
Aqui, a mantissa tem sete valores decimais (float – precisão fixa) e o expoente possui dois. A letra ‘E‘ significa “vezes dez elevado a“, significando que o valor 3.650000 multiplica 10 elevado a 02 (102). Ou seja:
3.650000 x 10 x 10 = 3.650000 x 100 = 365 (ignorando os zeros).
Note que o valor do expoente – 02 – é um valor positivo. Por padrão, não precisamos especificar o sinal do expoente se for positivo, como fizemos no exemplo. Mas se o valor for negativo, é obrigatório indicar seu sinal – e podemos indicar se for positivo também, para maior clareza de representação. Veja os exemplos do mundo real:
Carga elementar (elétron): 1.602 × 10-19 = 1.602E-19
Constante de Avogadro: 6.022 x 1023 = 6.022E23
Podemos usar essa notação ao definir constantes de ponto flutuante ou ainda valores literais em um programa (diretamente no código-fonte). A letra E pode ser maiúscula ou minúscula, não importando seu caso.
Os tipos de ponto flutuante disponíveis em C++ são:
Tipo | Faixa de Valores | Tamanho em bytes |
float | 1.17549 x 10-38 a 3.40282 x 1038 | 4 |
double | 2.22507 x 10-308 a 1.79769 x 10308 | 8 |
long double | Depende da implementação. Em meu sistema (Win 10 64 bits), por exemplo, os limites são: 3.3621 x 10-4932 a 1.18973 x 104932 |
10, 12 ou 16 |
O tipo float possui 7 dígitos de precisão (tamanho da mantissa), ao passo que o tipo double possui 15 dígitos de precisão (ou seja, precisão dupla). O arquivo de cabeçalho float.h informa os valores de bytes, expoente e precisão para os tipos de ponto flutuante do sistema em particular que você está usando.
Para descobrir os limites das faixas de valores dos tipos float, double e long double em seu sistema, você pode rodar o seguinte programa C++:
#include <iostream> #include <limits> using namespace std; int main() { cout << "Tipo\t\tValor Min\tValor Max\n\n" << "Float" << '\t' << '\t' << std::numeric_limits<float>::min() << '\t' << std::numeric_limits<float>::max() << '\n' << "Double" << '\t' << '\t' << std::numeric_limits<double>::min() << '\t' << std::numeric_limits<double>::max() << '\n' << "Long Double" << '\t'<< std::numeric_limits<long double>::min() << '\t' << std::numeric_limits<long double>::max() << '\n'; return 0; }
Veja o resultado do código anterior em meu sistema:
A escolha do tipo correto de dados é importante em seus programas para garantir que seja possível representar os dados de maneira eficiente e correta. Alguns exemplos disso incluem:
- usar o tipo short em vez de int se o intervalo de dados permitir
- usar double em vez de float para obter maior precisão para valores monetários (que representam dinheiro)
- usar um wchar_t para dados de caractere que não estão incluídos no conjunto de caracteres ASCII padrão, como por exemplo o Kanji japonês
Outros tipos de dados em C++ incluem os tipos de dados definidos pelo usuário (enum, structure, union e class) e tipos de dados derivados (array, ponteiro, referência), entre outros, que estudaremos em um momento oportuno.
Nas próximas lições vamos abordar de forma mais aprofundada conceitos como valores literais, os tipos char, wchar_t e bool, constantes, variáveis e outros.
Referências
- HORTON, I.; VAN WEERT, P. Beginning C++ 17 From Novice to Professional. 5ª edição. 2018. Editora Apress.
- PRATA, S. C++ Primer Plus. 6ª edição. 2012. Editora Addison-Wesley.
Bom dia Fábio,
Tudo bem?
Será que na primeira tabela não há algo estranho? Os dados do tipo primitivo int têm apenas uma faixa negativa de “-2.147.483.648 a -2.147.483.647”.
Até mais.