cblc/aulas/03-tipos-de-dados
2025-03-16 11:46:56 -03:00
..
dump.c conteúdo da aula 3 2025-03-16 11:46:56 -03:00
limites.c conteúdo da aula 3 2025-03-16 11:46:56 -03:00
quadrado-long.c conteúdo da aula 3 2025-03-16 11:46:56 -03:00
quadrado.c conteúdo da aula 3 2025-03-16 11:46:56 -03:00
README.org conteúdo da aula 3 2025-03-16 11:46:56 -03:00

Curso Básico da Linguagem C

Aula 3: Tipos de dados

Exemplo da última aula (quadrado.c)

#include <stdio.h>

int quadrado(int base) {
    return base * base;
}

int main(void) {
    int num = 100000;

    printf("%d^2 = %d\n", num, quadrado(num));
    return 0;
}

O que há de novo:

int num = 100000; → A base será 100.000

Compilando e executando…

:~$ gcc quadrado.c
:~$ ./a.out
100000^2 = 1410065408

O resultado está obviamente errado!

Tipos são tamanhos de dados na memória

  • Bit: algarismos 0 ou 1;
  • Byte: 8 bits;
  • Tipo int: 32 bits == 4 bytes (arquitetura x86_64).

Maior número que se pode escrever com 4 bytes (32bits):

(2^32) - 1 = 4.294.967.295

Quadrado de 100.000:

100.000^2 = 10.000.000.000

O que aconteceu?

Bytes necessários para escrever 10.000.000.000:

:~$ printf '0x%016x\n' 10000000000
0x00000002540be400
        ↑
        5 bytes

Bytes truncados pelo limite do tipo int (4 bytes):

:~$ printf '0x%016x\n' 1410065408
0x00000000540be400
          ↑
          4 bytes

Precisamos de mais espaço para escrever o resultado:

Tipo Tamanho Faixa de valores
char 1 byte -128 a 127
short 2 bytes -32.768 a 32.767
int 4 bytes -2.147.483.648 a 2.147.483.647
long 8 bytes -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807

Todos esses tipos consideram o uso de valores com sinal!

Exemplo corrigido (quadrado-long.c)

#include <stdio.h>

unsigned long quadrado(long base) {
    return base * base; /* Qual é o tipo dessa expressão? */
}

int main(void) {
    long num = 100000;

    printf("%ld^2 = %lu\n", num, quadrado(num));
    return 0;
}

## Compilando e executando…

:~$ gcc quadrado-long.c
:~$ ./a.out
100000^2 = 10000000000

Tipos primitivos

Tipo Tamanho Faixa de valores (x86_64)
char 1 byte -128 a 127
short 2 bytes -32.768 a 32.767
int 4 bytes -2.147.483.648 a 2.147.483.647
float 4 bytes 1,18E-38 a 3,40E+38
double 8 bytes 2,23E-308 a 1,80E+308

Qualificador unsigned (sem sinal):

Tipo Tamanho Faixa de valores (x86_64)
unsigned char 1 byte 0 a 255
unsigned short 2 bytes 0 a 65.535
unsigned int 4 bytes 0 a 4.294.967.295

Qualificador long:

Tipo Tamanho Faixa de valores (x86_64)
long 8 bytes -9223372036854775808 a 9223372036854775807
unsigned long 8 bytes 0 a 18446744073709551615
long double 16 bytes 3,36E-4932 a 1,19E+4932

Tipos customizados

Nós podemos criar apelidos para tipos:

typedef [QUALIFICADORES] TIPO NOME;

Exemplos:

typedef int i32;
typedef unsigned int u32;
typedef long int i64;
typedef unsigned long int u64;

Para diferenciar de nomes de variáveis, é comum utilizar o sufixo _t (de type):

typedef int i32_t;
typedef unsigned int u32_t;
typedef long int i64_t;
typedef unsigned long int u64_t;

Expressões constantes (valores literais)

EXPRESSÃO TIPO
42 int
42U unsigned int
42L long int
42UL unsigned long int
42LL long long int
42ULL unsigned long long int
'a' int
12.3 double
1e16 double
12.3F float
1e16F float
12.3L long double
1e16L long double
"salve" unsigned long (endereço)

O tipo void

No contexto de declarações de funções, void representa a ausência de tipo, mas pode ter outros significados.

Funções sem valor de retorno:

void func(int num) {
    printf("num x 2 = %d\n", num * 2);
}

Retorno não é o que a função imprime, mas o valor que ela expressa!

Funções que não recebem argumentos:

int func(void) {
    puts("Nada a fazer...");
    return 42;
}

Ponteiros de dados de tipo indeterminado:

void *ptr;

Ponteiros são variáveis que recebem endereços da memória (aula 5).

Modelagem de tipos (type casting)

Type casting é a conversão explícita de um tipo de dado para outro, utilizando a sintaxe (TIPO) antes de um valor ou de uma variável:

Exemplo:

(double)5    /* O inteiro '5' será compilado como 'double'. */