tipos.tex 7.93 KB
Newer Older
1 2 3 4
\documentclass[apostila.tex]{subfiles}


\begin{document}
5
\chapter{Especificadores e modificadores de
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
6 7 8
tipos}

\section{Casting}
9

10
Na linguagem C existem basicamente duas maneiras de converter uma variável de um tipo para outro:
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
11 12
implicitamente ou explicitamente. Uma conversão implícita é aquela que ocorre quando é realizada a
atribuição de uma variável de um determinado tipo para outra variável de um tipo diferente. O exemplo
13 14
abaixo ilustra uma conversão implícita.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
15
\begin{lstlisting}
16 17
int x;
float y=10.53;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
18 19
x=y; // aqui ocorre uma conversão implícita
\end{lstlisting}
20 21 22 23

Nem sempre a linguagem C aceita conversões implícitas, principalmente se os tipos de dados envolvidos
forem muito diferentes.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
24 25 26 27 28
\begin{lstlisting}
struct prod {
	int code;
	char nome[15];
};
29 30 31

struct prod var b;
int i;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
32 33
i = (var) b; // atribuição inválida!
\end{lstlisting}
34 35 36 37

Uma conversão explícita é quando o programador especifica qual o tipo que determinada variável deve
assumir, por exemplo, através de um casting.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
38
\begin{lstlisting}
39
int x;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
40
float y = 10.53;
41
x = (int) y; // o parênteses com o tipo é um casting
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
42
\end{lstlisting}
43

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
44 45
Assim como a conversão implícita, conversões explícitas entre tipos de dados muito diferentes também
não são válidas.
46 47

Basicamente, a única vantagem de um casting sobre uma conversão implícita é para determinar
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
48
exatamente qual o tipo de dado que uma determinada variável deve assumir.
49 50 51

Casting mudando resultados

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
52
\begin{lstlisting}
53 54 55 56
int a, b;
float c,d;

a=5; b=2;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
57 58 59
c=a/b; // c divisão entre inteiros
d=(float)a/(float)b; // d divisão entre floats
\end{lstlisting}
60

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
61 62
No exemplo anterior, embora a variável $c$ seja do tipo float, as variáveis $a$ e $b$ são inteiras, portanto
o resultado da divisão será $2$ e não $2,5$.
63 64 65 66

Isso acontece porque operações que envolvem dois números inteiros sempre resultam em um valor
inteiro.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
67
Por outro lado, a variável d assumirá o valor 2.5 porque foi especificado, através de casting, que as
68 69 70
variáveis a e b deveriam ser consideradas como float, o que obriga o programa a calcular a divisão entre
dois float's ao invés de dois números inteiros.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
71
\section{Variáveis Static}
72

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
73 74 75 76
Variáveis static são variáveis cujo valor é preservado entre sucessivas chamadas à função em que foi
declarada. Elas diferem das variáveis locais porque o seu valor não é destruído quando a função termina
e diferem das variáveis globais porque somente são visíveis dentro do contexto da função em que foram
declaradas. Observe o código abaixo:
77

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
\begin{lstlisting}
#include <stdio.h>

int prox_par(void)
{
	static int pares = -2;
	pares += 2;
	return (pares);
}

void main(void)
{
	int i;
	
	printf ("Os numeros pares menores que 100 sao: ");
	
	for(i=0; i < 100; i++)

	printf ("%d ", prox_par());
}
\end{lstlisting}

Este programa imprime na tela números pares, iniciando por zero, enquanto a variável i for menor
que 100, utilizando apenas a sucessiva chamada da função \verb|prox_par|.

O segredo está na variável static declarada. Ela é inicializada com o valor $-2$ quando o programa inicia
a execução. Na primeira chamada à função, essa variável é acrescida de $2$, resultando no valor $0$, que é
105 106
devolvido pela função.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
107 108
Na próxima chamada à função, o valor antigo da variável (zero) é preservado. Ela é então acrescida de
$2$, o valor $2$ $(0+2=2)$ é retornado e assim sucessivamente. Observe que se a variável não fosse declarada
109 110
como static, a função retornaria zero sempre.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
111 112 113 114
\subsubsection{Exercício}

Escreva uma função capaz de armazenar uma string e imprimir seu conteúdo. A função deverá ter apenas
um parâmetro (int p) e funcionará de modo que se $p=0$ a função obtêm e armazena a string e se $p=1$ a
115 116
função deverá apenas imprimir a string armazenada.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
117 118 119
\subsection{Variáveis Register}

Este modificador de tipo é tradicionalmente aplicado a variáveis do tipo int e char, embora possa ser
120 121 122
aplicado a outros tipos de dados também.

O modificador register requisita ao compilador que mantenha, se possível, o valor das variáveis
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
123
declaradas como register em registradores da CPU, ao invés de mantê-las na memória.
124

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
125 126
Isso significa que as operações com tais variáveis são muito mais rápidas, pois o valor já está na própria
CPU, economizando assim acessos à memória.
127

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
128 129
É importante observar que o ganho de desempenho só será significativo quando aplicado a 
variáveis muito utilizadas, como índices de matrizes e controladores de repetições.
130 131

Atualmente este modificador não é muito utilizado e tende a se tornar obsoleto, pois os compiladores
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
132 133
modernos vêm com recursos que analisam e otimizam automaticamente o código, de forma muito mais
eficiente (e rápida) que qualquer ser humano.
134

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
135
Exemplo de declaração:
136

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
137
\begin{lstlisting}
138
register int contador;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
139
\end{lstlisting}
140

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
141 142 143 144 145
\subsection{typedef}

A linguagem C permite definir explicitamente novos nomes de tipos de dados usando-se a 
palavra reservada typedef. Não é criado um novo tipo de dado, apenas definido um novo 
nome (apelido) para um tipo de dado existente.
146 147 148

A forma geral da declaração typedef é:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
149 150 151 152 153 154
\begin{lstlisting}
typedef tipo novo_nome;
\end{lstlisting}


onde tipo é qualquer tipo de dado válido e identificador é o novo nome para esse tipo. O novo nome
155 156 157 158
definido não substitui o nome do tipo, apenas é usado como um apelido para o mesmo.

Por exemplo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
159
\begin{lstlisting}
160 161 162
typedef float flutuante;
...
flutuante atraso;
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
163
\end{lstlisting}
164 165 166 167 168 169

O typedef é extremamente útil para simplificar nomes muito longos e complexos, como por exemplo,
nomes de estruturas.

Por exemplo:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
170 171 172 173 174
\begin{lstlisting}
typedef struct cliente {
	float divida;
	int atraso;
	char nome[40];
175
} cliente;
176 177

cliente lista[50];
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
178
\end{lstlisting}
179

180 181
Nesse exemplo, cliente não é uma variável do tipo struct cliente, mas um outro nome para struct
cliente.
182 183

O código a seguir é equivalente ao anterior.
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
184
\begin{lstlisting}
185
struct cliente {
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
186 187 188 189 190
	float divida;
	int atraso;
	char nome[40];
};

191 192
typedef struct cliente cliente;

193
cliente lista[50];
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
194 195 196
\end{lstlisting}

\subsection{Campos de bit (bit fields)}
197 198 199 200 201 202 203

A linguagem C permite que sejam acessados os bits individuais dentro de um tipo de dados maior como,
por exemplo, um byte.

Campos de bit são campos de uma estrutura formatados de modo a ocuparem uma quantidade de
bits definível pelo programador.

204
Éssa propriedade é muito útil quando se deseja definir estruturas que vão conter dados que, 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
205
normalmente, precisariam de menos que 8 bits (menor tamanho possível para um tipo de dado comum), ou
206 207
mesmo um dado que ocuparia uma quantidade de bits que não seja múltiplo de 8.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
208
A forma genérica para se definir um campo de bit é:
209

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
210 211 212 213 214 215
\begin{lstlisting}
struct nome estrutura{
	tipo var var : nbits;
	...
};
\end{lstlisting}
216 217 218 219 220 221

Onde, além dos elementos tradicionais de uma estrutura, existe um novo elemento denominado nbits,
que determina o tamanho, em bits, que a variável deve ocupar.

Observe que nbits não pode ser maior que o tamanho normal do tipo de dado tipo var.

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
222 223 224 225 226 227
\begin{lstlisting}
struct pessoa {
	char nome[30];
	int sexo: 1; // 0-> feminino , 1-> masculino
	int idade: 7;
	int estado civil: 2;
228 229 230 231
	// 0 -> solteiro
	// 1 -> casado
	// 2 -> desquitado
	// 3 -> viuvo 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
232
} pessoas[2];
233 234

int main ()
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
235 236
{
	pessoas[0].nome = "Jose Maria da Silva";
237
	pessoas[0].sexo = 1; // masculino 
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
238
	pessoas[0].idade = 34;
239
	pessoas[0].estado civil = 0; // solteiro
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
240 241
}
\end{lstlisting}
242

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
243
\subsection{Exercícios}
244 245 246

1. Defina uma estrutura para armazenar os seguintes campos:

Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
247 248 249 250 251 252 253
\begin{itemize}
	\item produto: [10 caracteres]
	\item pago: (valores que pode assumir: s/n)
	\item código: (valores que pode assumir: 0-31)
	\item setor: (valores que pode assumir: 0-3)
\end{itemize}

254 255 256 257 258 259 260

Defina duas estruturas, uma sem campos de bits e outra com campos de bits de modo a ocupar o
menor tamanho possível.

Baseado na tabela abaixo, compare a diferença entre os tamanhos de uma estrutura normal (sem
campos de bits) e uma estrutura com campos de bits.

261
\begin{center}
Jomaro Rodrigues's avatar
Jomaro Rodrigues committed
262 263 264 265 266
	\begin{tabular}{|l|l|}
		\hline char & 1 \\
		\hline int & 4 \\
		\hline
	\end{tabular}
267
\end{center}
268 269

\end{document}