#+title: Curso Básico da Linguagem C #+subtitle: Aula 3: Tipos de dados #+author: Blau Araujo #+startup: show2levels #+options: toc:3 * Aula 3: Tipos de dados - [[https://youtu.be/iMiRzZCU7hE][Vídeo desta aula]] - [[https://fiorix.wordpress.com/wp-content/uploads/2014/04/o-fantc3a1stico-mundo-da-linguagem-c.pdf][O Fantástico Mundo da Linguagem C - Alexandre Firori]] ** Exemplo da última aula (=quadrado.c=) #+begin_src c #include int quadrado(int base) { return base * base; } int main(void) { int num = 100000; printf("%d^2 = %d\n", num, quadrado(num)); return 0; } #+end_src O que há de novo: ~int num = 100000;~ → A base será 100.000 Compilando e executando... #+begin_example :~$ gcc quadrado.c :~$ ./a.out 100000^2 = 1410065408 #+end_example 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): #+begin_example (2^32) - 1 = 4.294.967.295 #+end_example Quadrado de 100.000: #+begin_example 100.000^2 = 10.000.000.000 #+end_example *** O que aconteceu? Bytes necessários para escrever 10.000.000.000: #+begin_example :~$ printf '0x%016x\n' 10000000000 0x00000002540be400 ↑ 5 bytes #+end_example Bytes truncados pelo limite do tipo =int= (4 bytes): #+begin_example :~$ printf '0x%016x\n' 1410065408 0x00000000540be400 ↑ 4 bytes #+end_example 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=) #+begin_src c #include 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; } #+end_src ## Compilando e executando... #+begin_example :~$ gcc quadrado-long.c :~$ ./a.out 100000^2 = 10000000000 #+end_example ** 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: #+begin_example typedef [QUALIFICADORES] TIPO NOME; #+end_example *** Exemplos: #+begin_src c typedef int i32; typedef unsigned int u32; typedef long int i64; typedef unsigned long int u64; #+end_src Para diferenciar de nomes de variáveis, é comum utilizar o sufixo =_t= (de /type/): #+begin_src c typedef int i32_t; typedef unsigned int u32_t; typedef long int i64_t; typedef unsigned long int u64_t; #+end_src ** 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: #+begin_src c void func(int num) { printf("num x 2 = %d\n", num * 2); } #+end_src #+begin_quote Retorno não é o que a função imprime, mas o valor que ela expressa! #+end_quote *** Funções que não recebem argumentos: #+begin_src c int func(void) { puts("Nada a fazer..."); return 42; } #+end_src *** Ponteiros de dados de tipo indeterminado: #+begin_src c void *ptr; #+end_src #+begin_quote Ponteiros são variáveis que recebem endereços da memória (aula 5). #+end_quote ** 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: #+begin_src c (double)5 /* O inteiro '5' será compilado como 'double'. */ #+end_src