[CAPÍTULO 1] - [CAPÍTULO 2] - [CAPÍTULO 3]
[PARTE 1] - [PARTE 2] - [PARTE 3] - [PARTE 4] - [PARTE 5] - [PARTE 6] - [PARTE 7] - [PARTE 8]
[PARTE 1] - [PARTE 2] - [PARTE 3] - [PARTE 4] - [PARTE 5] - [PARTE 6] - [PARTE 7] - [PARTE 8]
Operadores e Expressões: bit-a-bit e especiais
Objetivos:
Em C, OPERADORES e EXPRESSÕES podem ser classificados em cinco grande categorias:- Atribuições
- Aritméticos
- Lógicos e Relacionais
- Bit-a-Bit
- Especiais
- Bit-a-Bit
- Especiais
Manipulação de Bits:
OPERADORES e EXPRESSÕES de manipulação de bits ( bit-a-bit ) referem-se a testar, atribuir ou deslocar os bits efetivos em um byte ou palavra que correspondem aos tipos básicoschar, int e variantes.OBS.:
- Operações bit-a-bit não podem ser feitas sobre
float,double,long double,voidou outros tipos mais complexos.
Significados:
- Os operadores
&,|e~têm a mesma tabela verdade que&&,||e!(respectivamente), com a diferença que operam sobre os bits individuais da representação de dois números (ou apenas um, no caso de~) e não sobre expressões numéricas. - o operador
^tem a mesma tabela verdade que a funçãoxor()discutida na aula passada (novamente operando sobre bits individuais e não sobre expressões numéricas). - o operador
>>desloca os bits de um número k casas para à esquerda fazendo com que os k bits mais à esquerda se percam e os k bits mais à direita sejam '0' - o operador
<<desloca os bits de um número k casas para à direita fazendo com que os k bits mais à direita se percam e os k bits mais à esquerda sejam '0'
<< e >>):Considere:
unsigned int x = 7;Se pudéssemos olhar a representação do valor
7 (decimal) 'dentro' da variável x, veríamos os seguinte padrão de bits: x = 0...00000111 ( a quantidade total de bits depende de quantos bytes são utilizados para armazenar um unsigned int, quantidade que depende da máquina alvo e compilador ).A EXPRESSÃO abaixo (deslocamento à esquerda):
x = x << 2;faz com que o padrão de bits representando o valor inicial
7 se transforme em x = 0...00011100. Quer dizer, os bits, todos foram deslocados para a esquerda dois bits! Assim, o valor agora reresentado na variável x é 28 !De maneira geral, se uma variável tem o seguinte padrão de bits:
- x = | bn-1 | bn-2 | ... | b2 | b1 | b0 |
- onde:
- a variável é representada por n bits
- cada um dos bi (para 0 ≤ i ≤ n-1 ) denota um bit com valor '0' ou '1'
-
x << k, resulta em:- x = | bn-k-1 | bn-k-2 | ... | b2 | b1 | b0 | 0 | 0 | .. | 0 |0 | 0 |
- onde a seq. final de '0's contém k '0's
-
x >> k, resulta em:- x = | 0 | 0 | ... | 0 | 0 | 0 | bn-1 | bn-2 | ... | bk-1 | bk |
- onde a seq. inicial de '0's contém k '0's
Exemplo 2 (
~):Continuando o exemplo anterior, tem-se
x = 0...00011100. A EXPRESSÃO abaixo ( complemento de 1 ):
x = ~ x;tem o seguinte efeito na representação de x em binário:
x = 1...11100011 . Ou seja, os bits que são '0' passam a ser '1', os que são '1' tornam-se '0'. Exemplo 3 (
|):Continuando o exemplo anterior, tem-se
x = 1...11100011.A EXPRESSÃO abaixo ( OR ):
x = x | 8 ;transforma x em :
x = 1...11101011 . Quer dizer, muda o quarto bit (da direita para a esquerda) de '0' para '1'. Isto acontece por que:x = 1...11100011
4 = 0...00001000
--------------
x | 4 = 1...11101011 /* OU bit a bit */
-
|é frequentemente utilizado para LIGAR bits particulares
Exemplo 4 (
&):Continuando o exemplo anterior, tem-se
x = 1...11101011.A EXPRESSÃO abaixo ( AND ):
x = x & 0xf...f7 ;transforma x em :
x = 1...11100011 . Quer dizer, muda o quarto bit (da direita para a esquerda) de '1' para '0'. Isto acontece por que:x = 1...11101011
0xf...f7 = 1...11110111
--------------
x | 0xf...f7 = 1...11100011 /* AND bit a bit */
-
&é frequentemente utilizado para DESLIGAR bits particulares
Aplicações Típicas:
- rotinas de SO, drivers de dispositivos
- criptografia
- compactação de dados
Atividade 1:
Tendo em vista os significados de| e & que são, respectivamente, similares aos de || e &&, descreva - através de um exemplo - o significado de ^ que é similar à função xor() descrita na última aula.Atividade 2:
Uma tabela binária é uma tabela (matriz linhas x colunas ) onde cada célula armazena um dentre dois valores possíveis. Por exemplo, a Freqüência deste curso é em essência uma tabela binária uma vez que cada célula só pode conter ou '0' (presente) ou '2' (ausente).Uma maneira simples de representar uma tabela binária é através da seguinte estrutura:
char tabela1[40][10];Nesta representação são gastos : 40*10 = 400 bytes (
sizeof char = 1 byte ).Uma maneira mais eficiente (do ponto de vista da quantidade de memória utilizada) seria utilizar um mapa de bits para armazenar a tabela binária. Tal mapa de bits é uma sequencia de bits mantidas pelos operadores bit a bit.
Para a tabela acima de 40 linhas por 10 colunas poderíamos ter a seguinte declaração:
char tabela2[ (40*10) / 8 ];Nesta representação são gastos : (40*10)/8 = 50 bytes. A idéia aqui é, ao invés de usar um
char (1 byte) para armazenar 0 ou 1, usar um bit individual dentro de um char. Vejamos como isto pode ser feito.Atribuindo valor a uma determinada célula (linha,coluna)
Na primeira representação acima, uma dada célula pode ter seu valor modificado da seguinte maneira:
tabela1 [3][5] = 0; /* aluno 3 esteve presente */ tabela1 [7][5] = 2; /* aluno 7 faltou */
Na segunda representação acima, o mesmo processo tem de ser simulado através de uma função:
void set(unsigned x, unsigned y, int val) {
unsigned pos = ( x* 10 + y ) / 8;
unsigned des = ( x* 10 + y ) % 8;
if (val)
tabela2[pos] |= ( 1 << des );
else
tabela2[pos] &= ~( 1 << des );
}
Recuperado o valor em uma determinada célula (linha,coluna)
A consultar do valor em uma dada célula é feita de maneira direta para a primeira representação (utilizado índices linha e coluna). Já para a segunda representação devemos fazer uma função de consulta.
/* retorna 0 se na pos x,y está armazenado 0
retona 1 se na pos x,y está armazenado 1
**/
int get(unsigned x, unsigned y) {
...
}
Como exercício, escreva a função de consulta get().Operadores Especiais:
- Operador Condicional
? : - Operador
sizeof - Operadores de Conversão de Tipo ou Casting
(tipo) - Operador Vírgula
, - Operadores
()e[]
Serão vistos em mais detalhes em aulas futuras:
- Operadores de ponteiros
*e& - Operadores de estruturas
.e->
Operador Condicional ? :
UsoEXP1 ? EXP2 : EXP3;Significado
EXP1 é avaliada ... Se ela for verdadeira, então EXP2 é avaliada e se torna o valor da expressão como um todo. ... Se EXP1 for falsa, então EXP3 é avaliada e se torna o valor da expressão como um todo.
Por exemplo, o comando condicional da função
set() da atividade 2 poderia ser reescrito assim:tabela2[ pos ] = val ? tabela2[pos] | (1 << des) : tabela2[pos] & ~ (1 << des) ;
b) Operador sizeof
Usosizeof ID-VAR; sizeof (ESP-TIPO);Significado
sizeof é um operador unário em tempo de compilação que retorna o tamanho, em BYTES, de uma variável ou de um especificador de tipo de dados, este último escrito entre parênteses.Por exemplo, para tornar o código da função
set() da atividade 2 mais PORTÁVEL, podemos fazer:char tabela2 [ (40*10) / ((sizeof char)*8) + 1 ];
void set(unsigned x, unsigned y, int val) {
unsigned pos = ( x* 10 + y ) / ((sizeof char)*8);
unsigned des = ( x* 10 + y ) % ((sizeof char)*8);
...
}
c) Conversão Explícita de tipos (casting)
Uso(ESPECIFICADOR-DE-TIPO) EXPRESSÃO;Significado
Força - explicitamente - uma EXPRESSÃO a ser de um determinado tipo dado por
ESPECIFICADOR-DE-TIPO.Por exemplo, para deixar claro que em:
tabela2 |= ( 1 << des);o valor
1 se trata de um char ( 1 byte ) podemos fazer de forma explícita:tabela2 |= ( ((char) 1) << des );
Além de conversões explícitas, o compilador realiza algumas conversões implícitas ...
Conversões Automáticas
Exemplo:
d) Operador vígula ,
UsoEXP1, EXP2;Significado
O operador vígula é usado para encadear diversas expressões. O lado esquerdo (EXP1) é sempre avaliado como
void. Assim, a expressão do lado direito (EXP2) torna-se o valor de toda a expressão separada por vírgula.Por exemplo:
int x,y; x = ( y = 3, y+1 );primeiro o valor 3 é atribuído a
y e, em seguida, o valor 4 é atribuído a x. Os parênteses são necessários porque o operador vírgula tem a menor precedência de todos os operadores de C. Um outro exemplo é:
int i,x;
for ( i = 0 , x = 1; i < 10; i++ , x+=2) {
...
}
e) Operadores () e []
- Parênteses
()são operadores que aumentam a precedência das operações dentro deles. - Colchetes
[]realizam indexação de vetores e matrizes.
Quadro Geral de Operadores em C:
A tabela 2.8 lista a precedência de todos os operadores de C. Note que todos os operadores, exceto os operadores unários e o?, associam da esquerda para a direita. Os operadores unários ( *, ! e ~) e o ternário ? associam da direita para a esquerda.Ordem de Avaliação:
O padrão C ANSI (C89) não estipula que as subexpressões de uma expressão devam ser avaliadas e uma ordem específica. Assim, seu código nunca deve contar com a ordem em que as subexpressões são avaliadas. Por exemplo, a expressão:x = f() + g();não garante que
f() será chamada antes de g()!Leituras Recomendadas:
- CCT capítulo 2
- K&R capítulos 2
- http://pt.wikipedia.org/wiki/Operadores_em_C_e_C%2B%2B
- http://www.mspc.eng.br/info/cpp_oper_10.shtml
Exercícios
- Realize por completo a atividade 1
- Realize por completo a atividade 2, escrevendo a função
get()e testando as funçõesset()eget()em um programa que lê do usário posições x e y, liga os bits nestas posições e ao final imprime a tabela completa. - Observe o padrão abaixo:
- ( (0000 0001)2
<<1 ) → (0000 0010)2 = 2 - ( (0000 0010)2
<<1 ) → (0000 0100)2 = 4 - ( (0000 0100)2
<<1 ) → (0000 1000)2 = 8 - ( (0000 1000)2
<<1 ) → (0001 0000)2 = 16 - ( (0001 0000)2
<<1 ) → (0010 0000)2 = 32 - ...
- desse padrão, o que se pode concluir com relação à operação de deslocamento à esquerda?
- e com relação à operação de deslocamento à direita?
- em termos numéricos o que significa x
<<k ? Quer dizer, se x vale 5 quanto irá valer x<<k ? - em termos numéricos o que significa x
>>k ? Quer dizer, se x vale 35 quanto irá valer x>>k ?
- ( (0000 0001)2
- Para o programa abaixo, descreva como ele funciona e qual a saída gerada após a sua execução.
#include <stdio.h>
int g(float a, float b) {
static float f;
return f += a > b ? a / b : b / a , (int) f;
}
int main() {
printf("%i\n", g(7,2));
printf("%i\n", g(2,3));
}
Bibliografia e fonte:- [CCT] Schildt, H. (1996) C, completo e total: 3a Ed.. São Paulo, Makron.
- LP, UFMA; Coutinho, Lucian. Linguagem de programação para ciencia da computação da ufma.http://www.deinf.ufma.br/~lrc/2009.1/LP/
- [K&R] KERNIGHAN, B. e RITCHIE, D. (1990) C, a linguagem de programação: padrão ANSI. Rio de Janeiro: Campus.
- DEITEL, H. M. (1999) Como programar em C. Rio de Janeiro: LTC.
- Módulo Consultoria e Informática (1989) Linguagem C: programação e aplicações. Rio de Janeiro: LTC.
Coloque aqui o seu email