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 qual letra o printf usa para mostrá-la. 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,charebool. - Os "parentes":
short,long,long long,float,long double, e o tipo "nenhum valor",void. - Como medir o tamanho de um tipo com
sizeof, e por que olongtem 8 bytes no gcc e 4 no editor do guia. - A letra de cada tipo no
printf(%d,%ld,%f,%c…). - Por que o C não tem um tipo
string. - Como escolher o tipo certo para cada informação.
Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook, um PC comum de 64 bits), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -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.
- 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 quatro tipos do dia a dia
#include <stdio.h>
int main(void) {
int idade = 29;
double altura = 1.65;
char inicial = 'A';
bool cliente_vip = true;
printf("Idade: %d\n", idade);
printf("Altura: %.2f\n", altura);
printf("Inicial: %c\n", inicial);
printf("VIP: %d\n", cliente_vip);
return 0;
}
$ gcc -std=c23 -Wall -Wextra tipos.c -o tipos $ ./tipos Idade: 29 Altura: 1.65 Inicial: A VIP: 1 « true aparece como 1 (a aula bool explica)
| Tipo | Nome vem de | Guarda | Como se escreve o valor | printf | Aula |
|---|---|---|---|---|---|
int | integer, "inteiro" | Números inteiros, positivos ou negativos | 29, -7, 0 | %d | Inteiros |
double | double precision, "precisão dupla" | Números com vírgula (fração) | 1.65, -0.5, 3.0 (com ponto) | %f | float e double |
char | character, "caractere" | Um caractere (por dentro, um número pequeno) | 'A', '7', '?' (aspas simples) | %c | Caracteres |
bool C23 | George Boole, matemático | Verdadeiro ou falso | true, false | %d (mostra 1 ou 0) | Booleanos |
Com esses quatro 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. O bool sem #include é novidade do C23; em código mais antigo você vai ver #include <stdbool.h> no topo (a aula Booleanos conta a história).
Missão: rode e veja a ficha da Ana. Depois crie uma variável bool pago valendo false e mostre-a numa linha nova, Pago: 0, com %d. Se quiser, tente também pôr "A" (com aspas duplas) no char inicial e leia o erro: um char guarda um caractere, entre aspas simples.
#include <stdio.h>
int main(void) {
int idade = 29;
double altura = 1.65;
char inicial = 'A';
printf("Idade: %d\n", idade);
printf("Altura: %.2f\n", altura);
printf("Inicial: %c\n", inicial);
return 0;
}
#include <stdio.h>
int main(void) {
int idade = 29;
double altura = 1.65;
char inicial = 'A';
bool pago = false;
printf("Idade: %d\n", idade);
printf("Altura: %.2f\n", altura);
printf("Inicial: %c\n", inicial);
printf("Pago: %d\n", pago);
return 0;
}
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. O resultado é de um tipo especial para tamanhos, o size_t, que o printf mostra com %zu (z de size, u de unsigned, "sem sinal"; detalhes em Tamanho dos Tipos):
#include <stdio.h>
int main(void) {
printf("bool: %zu\n", sizeof(bool));
printf("char: %zu\n", sizeof(char));
printf("short: %zu\n", sizeof(short));
printf("int: %zu\n", sizeof(int));
printf("long: %zu\n", sizeof(long));
printf("long long: %zu\n", sizeof(long long));
printf("float: %zu\n", sizeof(float));
printf("double: %zu\n", sizeof(double));
printf("long double: %zu\n", sizeof(long double));
return 0;
}
$ gcc -std=c23 -Wall -Wextra tamanhos.c -o tamanhos $ ./tamanhos bool: 1 char: 1 short: 2 int: 4 long: 8 long long: 8 float: 4 double: 8 long double: 16
Os espaços depois dos nomes ("int: ") estão lá só para alinhar a saída em colunas.
A tabela completa
| Tipo | Bytes no gcc 15 (Linux 64 bits) | Bytes no editor do guia | Guarda | Faixa aproximada | printf |
|---|---|---|---|---|---|
bool | 1 | 1 | verdadeiro/falso | true ou false | %d |
char | 1 | 1 | um caractere (um número pequeno por dentro) | -128 a 127 | %c (ou %d para ver o número) |
short | 2 | 2 | inteiro pequeno | -32 768 a 32 767 | %hd |
int | 4 | 4 | inteiro (o padrão) | cerca de ±2,1 bilhões | %d |
long | 8 | 4 | inteiro "grande" | ±9,2 quintilhões no gcc; ±2,1 bilhões no editor | %ld |
long long | 8 | 8 | inteiro grande (8 bytes em todo lugar) | cerca de ±9,2 quintilhões | %lld |
float | 4 | 4 | número com vírgula, precisão simples | uns 6 a 7 dígitos certos | %f |
double | 8 | 8 | número com vírgula, precisão dupla (o padrão) | uns 15 a 16 dígitos certos | %f |
long double | 16 | 16 | número com vírgula, mais precisão | uns 18 dígitos certos no gcc | %Lf |
Os limites exatos de cada inteiro (com limits.h) 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, e Formatos do printf explica cada letra.
A norma do C só garante mínimos: int tem pelo menos 16 bits (2 bytes), long pelo menos 32 bits (4 bytes), long long pelo menos 64 bits (8 bytes). Os números da coluna do gcc valem para o Linux 64 bits da Ana. No Windows, long tem 4 bytes. No editor do guia, que roda como um computador "de 32 bits" (WebAssembly), long também tem 4 bytes: rode o tamanhos.c lá e confira. Quando o tamanho exato importa, use long long ou os tipos de tamanho fixo, como int64_t (aula Inteiros de Tamanho Fixo).
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:
#include <stdio.h>
int main(void) {
printf("%zu %zu %zu %zu %zu %zu\n",
sizeof(42), sizeof(4.5), sizeof(4.5f), sizeof('A'), sizeof(true), sizeof("Ana"));
return 0;
}
$ gcc -std=c23 -Wall -Wextra literais.c -o literais $ ./literais 4 8 4 4 1 4
| Literal | Tipo | Bytes | Por quê |
|---|---|---|---|
42 | int | 4 | Número sem ponto. |
4.5 | double | 8 | Número com ponto. |
4.5f | float | 4 | O f no fim pede float. |
'A' | int (!) | 4 | Surpresa do C: um caractere entre aspas simples é um int, não um char. Ele cabe num char sem problema (aula Caracteres). Em C++ seria 1. |
true | bool | 1 | Palavra-chave de verdadeiro no C23. |
"Ana" | array de char | 4 | Três letras e um caractere invisível no fim, o '\0', que marca onde o texto termina (aula Strings). |
3. E o texto? O C não tem tipo string
Quem vem de Python, JavaScript ou mesmo do C++ procura um tipo string para guardar nomes e frases. Em C, ele não existe:
#include <stdio.h>
int main(void) {
string nome = "Ana";
printf("%s\n", nome);
return 0;
}
$ gcc -std=c23 -Wall -Wextra semstring.c -o semstring
semstring.c: In function ‘main’:
semstring.c:4:5: error: unknown type name ‘string’; did you mean ‘stdin’?
4 | string nome = "Ana";
| ^~~~~~
| stdin
semstring.c:4:19: error: initialization of ‘int’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
4 | string nome = "Ana";
| ^~~~~
semstring.c:5:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
5 | printf("%s\n", nome);
| ~^ ~~~~
| | |
| | int
| char *
| %d
- unknown type name ‘string’
- "Nome de tipo desconhecido:
string". Odid you mean ‘stdin’?é um chute do gcc por um nome parecido; não tem nada a ver com o seu problema. - initialization of ‘int’ from ‘char *’
- Sem saber o que é
string, o gcc imaginou quenomefosse uminte reclamou do texto. É um erro em cascata: conserte o primeiro e este some.
Em C, um texto é uma fileira de char, um array, com o '\0' no fim. Por enquanto, basta reconhecer o formato; ele tem várias aulas próprias a partir de Arrays e Strings:
#include <stdio.h>
int main(void) {
char nome[] = "Ana";
printf("Nome: %s\n", nome);
printf("Tamanho: %zu bytes\n", sizeof(nome));
return 0;
}
$ gcc -std=c23 -Wall -Wextra texto.c -o texto $ ./texto Nome: Ana Tamanho: 4 bytes « 'A', 'n', 'a' e o '\0'
Os colchetes [] dizem "uma fileira de", e o %s (string) mostra o texto todo. Isso é o mais longe que o guia vai com textos antes da aula certa.
4. void: o tipo "nenhum valor"
O void ("vazio") é um tipo que quer dizer nada. Não existe variável void: não há o que guardar. Ele aparece em dois lugares que você já viu:
- int main(void)
- Dentro dos parênteses,
voiddiz "esta função não recebe nada". - void prepara(void)
- Antes do nome, diz "esta função não devolve nada" (aula Funções). Você viu uma assim em Variáveis.
Mais adiante ele volta como void *, um "endereço de qualquer coisa" (aula Ponteiro void*).
5. 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 preco_centavos = 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 | array de char | char cidade[] = "Recife"; |
| Um número de telefone, CEP ou CPF | array de char (!) | char cep[] = "01310-100"; |
O 8'100'000'000 usa o separador de dígitos do C23: os apóstrofos só ajudam a ler e são ignorados pelo compilador (aula Inteiros).
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 <stdio.h>
int main(void) {
int preco = 4.99;
int peso_kg = 2.5;
double total = preco * peso_kg;
printf("Total: %.2f\n", total);
return 0;
}
$ gcc -std=c23 -Wall -Wextra errado.c -o errado $ ./errado Total: 8.00 « 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 gcc não avisou com -Wall -Wextra. O Clang do editor avisa, porque os números estão escritos direto no código: implicit conversion from 'double' to 'int' changes value from 4.99 to 4 [-Wliteral-conversion].
Missão: conserte os tipos (só os tipos, sem mudar os números) para o total da feira da Ana sair certo: Total: 12.48, sem avisos. Leia os avisos do Clang primeiro: eles apontam exatamente as linhas a consertar.
#include <stdio.h>
int main(void) {
int preco = 4.99;
int peso_kg = 2.5;
double total = preco * peso_kg;
printf("Total: %.2f\n", total);
return 0;
}
#include <stdio.h>
int main(void) {
double preco = 4.99;
double peso_kg = 2.5;
double total = preco * peso_kg;
printf("Total: %.2f\n", total);
return 0;
}
A conta exata é 4,99 × 2,5 = 12,475. O %.2f arredondou para duas casas e mostrou 12.48. (Com %.3f sairia 12.475.)
Quando dá errado
error: unknown type name ‘string’
O que significa: o C não tem tipo string. (O mesmo erro aparece com qualquer tipo escrito errado, como Int ou doble.)
Como consertar: para texto, use um array de char: char nome[] = "Ana"; (aula Strings). Para um tipo escrito errado, confira as letras: todos os tipos do C são em minúsculas.
error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast
O que significa: você escreveu char inicial = "A";, com aspas duplas. Aspas duplas fazem um texto, mesmo com uma letra só:
$ gcc -std=c23 -Wall -Wextra aspas.c -o aspas
aspas.c: In function ‘main’:
aspas.c:4:20: error: initialization of ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
4 | char inicial = "A";
| ^~~
Como consertar: um caractere vai entre aspas simples: char inicial = 'A';.
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’
O que significa: cada tipo tem a sua letra no printf, e long usa %ld:
$ gcc -std=c23 -Wall -Wextra longd.c -o longd
longd.c: In function ‘main’:
longd.c:5:14: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
5 | printf("%d\n", habitantes);
| ~^ ~~~~~~~~~~
| | |
| int long int
| %ld
$ ./longd
213000000 « desta vez saiu certo, por sorte
Como consertar: use a letra que o gcc sugere na última linha (%ld). O número saiu certo aqui, mas com a letra errada o printf pode ler bytes a mais ou a menos e mostrar lixo; o resultado depende da máquina. Nunca ignore um aviso -Wformat.
8.00 em vez de 12.48)
O que significa: uma variável que deveria guardar fração foi declarada como int. O gcc não avisa com -Wall -Wextra; com -Wconversion, avisa.
Como consertar: use double para tudo que pode ter vírgula. Veja também Conversão de Tipos.
Referência rápida
| Tipo | Exemplo | printf | Bytes (gcc / editor) |
|---|---|---|---|
char | char c = 'A'; | %c | 1 / 1 |
short | short s = 100; | %hd | 2 / 2 |
int | int n = 29; | %d | 4 / 4 |
long | long l = 100000L; | %ld | 8 / 4 |
long long | long long g = 8'100'000'000; | %lld | 8 / 8 |
float | float f = 1.5f; | %f | 4 / 4 |
double | double d = 1.65; | %f | 8 / 8 |
long double | long double x = 1.5L; | %Lf | 16 / 16 |
bool | bool ok = true; | %d | 1 / 1 |
void | int main(void) | (nenhum valor) | - |
| texto | char nome[] = "Ana"; | %s | letras + 1 |
sizeof(...) | sizeof(int) | %zu | - |
Exercícios
1. O tipo da altura
Complete com o tipo certo para guardar 1.72:
2. A letra do printf
Complete o formato para mostrar um long:
3. Quantos bytes tem um long?
4. Qual tipo você usaria para guardar um CEP como 01310-100?
5. O que acontece com string nome = "Ana"; em C?
6. Em C, quantos bytes tem sizeof('A') no gcc do laboratório?
Missão final: a ficha do produto
Missão: a lojinha da Ana precisa de uma ficha para cada produto. Declare quatro variáveis, cada uma com o tipo certo: o código do produto (a letra 'B'), a quantidade em estoque (12), o preço (3.75) e se está disponível (true). Depois complete o printf com as letras certas (%c, %d, %.2f, %d) para mostrar a linha abaixo, sem avisos.
Produto B: 12 unidades a 3.75 (disponível: 1)
#include <stdio.h>
int main(void) {
// declare as quatro variáveis aqui
printf("Produto ...\n");
return 0;
}
#include <stdio.h>
int main(void) {
char codigo = 'B';
int quantidade = 12;
double preco = 3.75;
bool disponivel = true;
printf("Produto %c: %d unidades a %.2f (disponível: %d)\n",
codigo, quantidade, preco, disponivel);
return 0;
}
Resumo
- O tipo diz o que cabe na caixa, quanto espaço ela ocupa e qual letra o
printfusa. - Do dia a dia:
int(%d),double(%f),char(%c) ebool(%d, sem#includeno C23). - Parentes:
short,long(%ld),long long(%lld),float,long double(%Lf).voidé "nenhum valor". sizeofmede em bytes (mostre com%zu). A norma só garante mínimos:longtem 8 bytes no gcc do Linux 64 bits e 4 no editor e no Windows.- Literais têm tipo:
42éint,4.5édouble,4.5féfloate, em C,'A'éint. - O C não tem tipo
string: texto é um array decharterminado em'\0'. - O tipo errado quase nunca dá erro; dá resposta errada. Escolha pelo que você quer guardar.