Artigo original: https://www.freecodecamp.org/news/data-types-in-c-integer-floating-point-and-void-explained/

Tipos de dados em C

Há várias maneiras diferentes de se armazenar dados em C. São todas únicas em relação umas às outras. Os tipos de dados na forma em que uma informação pode ser armazenada são chamados de tipos de dados. O C não lida com a diversidade de tipos de dados como outras linguagens. Como resultado, é importante garantir que você entende os tipos de dados existentes, suas capacidades e limitações.

Uma característica diferente dos tipos de dados em C está no fato de que eles dependem inteiramente do hardware no qual você está executando seu código. Um int no seu laptop será menor do que um int em um supercomputador. Desse modo, conhecer as limitações do hardware no qual você está trabalhando é importante. É por isso que os tipos de dados são definidos como sendo mínimos – um valor int, como você verá, é no mínimo de -32767 a 32767: em certas máquinas, ele poderá armazenar ainda mais valores do que esses.

Existem duas categorias que podemos usar para dividir esses valores: números inteiros e números de ponto flutuante. Os números inteiros são aqueles que não têm casas decimais. Podem ser positivos, negativos ou o zero. Números como -321, 497, 19345 e -976812 são números inteiros válidos. Já 4.5 não é válido por não ser um número sem casas decimais.

Números de ponto flutuante, por outro lado, são aqueles com casas decimais. Assim como os números inteiros, como -321, 497, 19345 e -976812 são todos válidos (podemos imaginar algo como .00 como sua "extensão"), agora, números como 4.5, 0.0004, -324.984 e outros números com casas decimais também são válidos.

O C nos permite escolher entre diversos tipos de dados, pois eles são todos armazenados de modos diferentes no computador. Como resultado, é importante estar atento às habilidades e limitações de cada tipo de dado para selecionar o mais apropriado.

Tipos de dados inteiros

Caracteres: char

char são letras ou outros caracteres assemelhados, como pontuação e espaços. Em um computador, os caracteres são armazenados como números. Assim, char possui números inteiros que representam os caracteres. A tradução de fato é descrita pelo padrão ASCII. Aqui vemos uma tabela útil para consulta.

O tamanho real, assim como ocorre com outros tipos de dados em C, depende do hardware com o qual você está trabalhando. Como mínimo, ele tem pelo menos 8 bits, o que nos traz números entre 0 e 127. Como alternativa, é possível usar signed char para obter, pelo menos, de -128 a 127.

Números inteiros padrão: int

A quantidade de memória que um único int utiliza depende do hardware. No entanto, você pode esperar que um int tenha, pelo menos, 16 bits. Isso significa que ele pode armazenar valores de -32,768 a 32,767 ou mais, dependendo do hardware.

Assim como ocorre com os outros tipos de dados, há uma variante unsigned (sem sinal) que pode ser usada. O unsigned int pode ser positivo ou zero, mas não negativo. Por isso, ele pode armazenar valores de 0 a 65,535 ou mais, dependendo do hardware.

Inteiros curtos: short

Esses não são usados com muita frequência, mas é bom saber que eles existem. Assim como ocorre com o int, ele pode armazenar de -32768 a 32767. Diferente do int, no entanto, essa é a extensão de sua capacidade. Onde você puder usar short, poderá usar int.

Inteiros longos: long

O tipo de dado long armazena números inteiros, como o int, mas oferece um intervalo maior de valores com o custo de ocupar mais memória. long armazena ao mesmo 32 bits, o que lhe confere um intervalo de -2,147,483,648 a 2,147,483,647. Como alternativa, pode-se usar unsigned long para um intervalo de 0 a 4,294,967,295.

Inteiros ainda mais longos: long long

O tipo de dados long long é um excesso para quase todo tipo de aplicação, mas o C permitirá que você o use. Ele é capaz de armazenar, ao menos, de −9,223,372,036,854,775,807 a 9,223,372,036,854,775,807. Como alternativa, temos um excesso ainda maior com o unsigned long long, que permite que se use, pelo menos, de 0 a 18,446,744,073,709,551,615.

Tipos de dados de números de ponto flutuante

Números de ponto flutuante básicos: float

float ocupa pelo menos 32 bits de armazenamento, mas nos dá 6 casas decimais, de 1.2E-38 a 3.4E+38.

Double: double

double recebe o dobro da memória de float (ou seja, pelo menos, 64 bits). Por sua vez, double pode fornecer 15 casas decimais, de 2.3E-308 a 1.7E+308.

Um intervalo ainda maior para double: long double

long double ocupa, pelo menos, 80 bits. Como resultado, podemos obter 19 casas decimais, de 3.4E-4932 a 1.1E+4932.

Escolhendo o tipo de dado certo

A linguagem C faz com que precisemos ser bem específicos na escolha do tipo de dados e termos uma intenção clara ao fazer isso. Isso dá a você muito poder sobre seu código, mas é importante saber escolher certo.

Em geral, você deve buscar o mínimo necessário para sua tarefa. Se souber que contará números inteiros de 1 a 10 somente, não é necessário usar long nem double. Se souber que nunca precisará de números negativos, busque usar as variantes unsigned dos tipos de dados. Ao fornecer essa funcionalidade em vez de fazer isso automaticamente, o C consegue produzir um código muito leve e eficiente. Porém, você é o responsável, em sendo o programador, por entender as capacidades e as limitações e por escolher os tipos de dados adequadamente.

Podemos usar o operador sizeof() para verificar o tamanho de uma variável. Confira o programa em C abaixo para conferir o uso de memória dos vários tipos de dados:

#include <stdio.h>

int main()
{
    int a = 1;
    
    char b ='G';
    
    double c = 3.14;
    
    printf("Ola mundo!\n");
 
    //Imprimindo as variáveis definidas acima junto do tamanho de cada uma
    printf("Ola! Eu sou um caractere. Meu valor e %c e "
           "eu tenho %lu bytes de tamanho.\n", b,sizeof(char));
    //Também é possível usar sizeof(b) acima
 
    printf("Ola! Eu sou um numero inteiro. Meu valor e %d e "
           "eu tenho %lu bytes de tamanho.\n", a,sizeof(int));
    //Também é possível usar sizeof(a) acima
 
    printf("Ola! Eu sou uma variavel double de ponto flutuante."
           "Meu valor e %lf e eu tenho %lu bytes de tamanho.\n",c,sizeof(double));
    //Também é possível usar sizeof(c) acima
 
    printf("Ate a proxima! :)\n");
    return 0;
}

Resultado:

Ola mundo!
Ola! Eu sou um caractere. Meu valor e G e eu tenho %lu bytes de tamanho.
Ola! Eu sou um numero inteiro. Meu valor e 1 e eu tenho 4 bytes de tamanho.
Ola! Eu sou uma variavel double de ponto flutuante. Meu valor e 3.140000 e eu tenho 8 bytes de tamanho.
Ate a proxima! :)

O tipo void

O tipo void especifica que não há um valor disponível. Ele é usado em três situações:

1. Retornos de função como void

Existem várias funções em C que não retornam valor ou que se pode dizer que retornam um valor vazio (em inglês, void). Uma função sem valor de retorno tem o tipo de retorno void. Por exemplo, void exit (int status);

2. Argumentos de função como void

Existem várias funções em C que não aceitam parâmetros. Uma função sem parâmetros pode aceitar um valor void. Por exemplo, int rand(void);

3. Ponteiros para void

Um ponteiro do tipo void * representa o endereço de um objeto, mas não seu tipo. Por exemplo, uma função de alocação de memória void *malloc( size_t size); retorna um ponteiro para void, que pode ser convertido para qualquer tipo de dados.