Você está na página 1de 15

MAC 122 PDA Marcilio Revisado 11Ago10

Expresses lgicas, expresses condicionais, prioridades e operadores, base binria, operadores de bits
Equivalncia entre valores lgicos e aritmticos Quando uma expresso lgica calculada dentro do programa, feita a seguinte associao numrica com o valor da expresso: verdadeiro 1 falso 0 O valor zero est associado ao valor lgico falso, enquanto que qualquer valor diferente de zero est associado ao valor lgico verdadeiro. Assim, uma comparao como, por exemplo, a > b, quando calculada, tem associado a si o valor 1 se a > b (verdadeira) e 0 se a <= b (falsa). Da mesma forma uma expresso aritmtica como, por exemplo, a + b, pode ser considerada falsa ou verdadeira, conforme seu valor seja zero ou diferente de zero. O programa abaixo mostra algumas variaes e exemplos da utilizao de expresses aritmticas como lgicas e vice-versa. Verifique o que ser impresso abaixo:
#include <stdio.h> int main() { char a; int b; int x = 0, y = 1; /* os valores atribuidos a a expresso verdadeira ou a = x < y; printf ("\n (1) valor de a = a = x < y && y > 0; printf ("\n (2) valor de a = a = x > y; printf ("\n (3) valor de a = b = x+y < x*y || x == y; printf ("\n (4) valor de a =

e b so zero e um, dependendo se a falsa */ %5d",a); %5d",a); %5d",a); %5d",b);

/* comparaes */ if (1) printf ("\n (5) sempre verdadeiro"); if (-5) printf ("\n (6) sempre verdadeiro"); if (0) ; else printf ("\n (7) sempre falso"); if (1 == 1) printf ("\n (8) sempre verdadeiro"); if (0 == 0) printf ("\n (9) sempre verdadeiro"); /* a tambm pode receber valores aritmticos entre 0 e 255 */ a = x * y; if (a) printf ("\n (10) verdadeiro quando a diferente de zero - a = %2d", a); else printf ("\n (10) falso quando a igual a zero - a = %2d", a);
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

/* a e b como valores lgicos */ a = x * y; b = x + y; if (a && b) printf ("\n (11) verdadeiro se a e b nao zero: a = %2d b = %2d",a,b); else printf ("\n (11) falso se a ou b sao zero: a = %2d b = %2d",a,b); b = 0; /* a repetio ser infinita */ while (1) { if (b++ > 4) break; // fora a sada printf("\n (%2d) valor de b = %2d", 11+b, b); } /* outro exemplo de while */ a = 1; b = 0; while (a) { printf("\n (%2d) valor de a = %2d valor de b = %2d", 18+b, a, b); a = (b++) < 3; } printf("\n (%2d) valor final de a = %2d e de b = %2d", 18+b, a, b); } (1) valor de a = 1 (2) valor de a = 1 (3) valor de a = 0 (4) valor de a = 0 (5) sempre verdadeiro (6) sempre verdadeiro (7) sempre falso (8) sempre verdadeiro (9) sempre verdadeiro (10) falso quando a igual a zero - a = 0 (11) falso se a ou b sao zero: a = 0 b = (12) valor de b = 1 (13) valor de b = 2 (14) valor de b = 3 (15) valor de b = 4 (16) valor de b = 5 (18) valor de a = 1 valor de b = 0 (19) valor de a = 1 valor de b = 1 (20) valor de a = 1 valor de b = 2 (21) valor de a = 1 valor de b = 3 (22) valor final de a = 0 e de b = 4

Supondo int x,y; as seguintes expresses lgicas so equivalentes:


(x && y) (x || y) (x != 0 && y != 0) (x != 0 || y!= 0) !(x == 0 || y == 0) !(x == 0 && y == 0)

MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

Lembram-se daquele problema que dada uma seqncia terminada por zero, calcular a soma dos elementos da seqncia?
int soma, x; : : x = 1; soma = 0; while (x) { scanf(%d, &x); soma = soma + x; } printf (o valor da soma = %d, soma);

Otimizao do clculo de expresses lgicas Quando se usa uma expresso composta, com os operadores && e ||, o compilador otimiza o clculo das mesmas, quando o valor j est definido no meio do clculo. Por exemplo, considere a expresso (a > b && c > d). Se a > b j falso, no necessrio verificar se c > d, pois o resultado da expresso j ser falso. O mesmo ocorre com (a > b || c > d). Se a > b verdadeiro, a expresso verdadeira independente se c > d ou no. Normalmente os compiladores da linguagem C usam esta regra como padro, sendo possvel alter-la atravs de uma opo de compilao para que o clculo seja completo. Em alguns casos, h efeitos colaterais provocados pelo clculo da expresso. O uso de expresses que pressupe a otimizao de clculo deve ser feito com muito cuidado, para evitar tais efeitos colaterais. Considere por exemplo a seguinte soluo para verificar se x igual a algum elemento de um vetor a de n elementos. Lembre-se que os elementos so a[0],a[1],...,a[n-1].
i = 0; while (i < n && a[i] != x) i++;

Considerando o caso em que x no igual a nenhum dos elementos, o programa sai do while quando i = n e no realiza a comparao a[i] != x. Se comparasse estaria errado, pois o elemento a[n]est fora dos n elementos considerados. Invertendo agora a expresso acima:
i = 0; while (a[i] != x && i < n) i++;

Embora a operao && seja comutativa, a soluo acima est errada, pois quando i = n a comparao a[n] != x ser efetuada, pois vem antes da comparao i < n. Expresses condicionais
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

Considere o comando abaixo:


/* atribui a c o maior entre a e b */ if (a > b) c = a; else c = b;

O mesmo resultado pode ser obtido usando-se uma expresso condicional com o operador ternrio ?: da seguinte forma:
c = (a > b) ? a : b;

Como muitas construes em C, o uso do operador ?: compacta demais (pouco clara), porm s vezes facilita. A forma geral de uma expresso condicional : expresso1? expresso2: expresso3 A expresso1 calculada. Se seu valor for verdadeiro, calculado o valor de expresso2, seno calculado o valor de expresso3. Somente um dos valores expresso1 ou expresso2 calculado. Considere o seguinte programa abaixo que imprime os nmeros de 0 a 99, dez deles por linha. Aps cada nmero, com exceo do ltimo de cada linha, impresso -:
#include <stdio.h> int main() { int i; for (i = 0; i < 100; i++) printf("%5d%1c", i, (i%10 == 9) ? '\n' : '-'); } 0102030405060708090111213141516171819121222324252627282923132333435363738393414243444546474849451525354555657585956162636465666768696717273747576777879781828384858687888989 19 29 39 49 59 69 79 89 99

Tabela de operadores e suas prioridades de avaliao A tabela abaixo mostra os operadores do c, em ordem decrescente de prioridade de clculo:
Prioridade 1 2 3 4
MAC 122 PDA Marcilio Revisado 11Ago10

Operadores () [] -> . ! ~ ++ -- + - (tipo) * & sizeof * / % + -

Obs: esquerda para direita direita para esquerda esquerda para direita esquerda para direita

MAC 122 PDA Marcilio Revisado 11Ago10

5 6 7 8 9 10 11 12 13 14 15

<< >> esquerda para direita < <= > >= esquerda para direita == != esquerda para direita & esquerda para direita ^ esquerda para direita | esquerda para direita && esquerda para direita || esquerda para direita ?: direita para esquerda = += -= *= /= %= <<= >>= &= |= ^= direita para esquerda , esquerda para direita

Os unrios +, - e * (linha 2) tem maiores prioridades que os binrios correspondentes. Os operadores -> e . so usados em structs . O operador sizeof(tipo) devolve o tamanho em bytes do tipo. Muito cuidado deve ser tomado com a mistura excessiva de operadores numa expresso, devido definio das prioridades. Na dvida use parntesis. Por exemplo:
if (x & 5 == 0)

diferente de if( (x & 5) == 0). Veja a tabela acima.

Alm disso, na linguagem C no especificada (definida) a ordem de avaliao dos operandos de um operador. Assim compiladores diferentes podem levar a resultados diferentes. Portanto no uma boa prtica de programao, usar comandos cujo resultado depende da ordem de avaliao dos seus operandos. Exemplo:
a = exp1 + exp2 (quem calculado primeiro exp1 ou exp2?)

Da mesma forma a ordem de clculo dos parmetros de funo no est definido no C. Por exemplo, se n 5: func(n, n++); pode ser func(5, 6) ou func(6,6)

Nmeros na base 2 Para o prximo assunto bom uma recordao de como se escreve nmeros na base binria: Um nmero na base 2 possui apenas os algarismos 0 e 1, da mesma forma que um nmero na base 10 possui algarismos de 0 a 9. O nmero 1235 na base 10 significa 5 + 3*10 + 2*100 + 1*1000. O nmero 10101 na base 2 significa 1 + 0*2 +1*4 + 0*8 + 1*16 = 21.
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

Alguns exemplos de nmeros na base 2.


base 10 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 base 2 0 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111

Dado um nmero na base 10, escrev-lo na base 2. Lembram-se do algoritmo? Basta ir dividindo o nmero por 2 at acabar e ir pegando os restos na ordem inversa.
Quociente 25 12 6 3 1 0 resto da diviso por 2 1 0 0 1 1

25 na base 10 = 11001 na base 2


Quociente 67 33 16 8 4 2 1 0 resto da diviso por 2 1 1 0 0 0 0 1

67 na base 10 = 1000011 na base 2 Este mesmo mtodo pode ser usado para escrever um nmero em qualquer base. Vejamos por exemplo na base 7.
Quociente resto da diviso por 7

MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

276 39 5 0

3 4 5

276 na base 10 = 543 na base 7 (de fato 3 + 4*7 + 5*49 = 276) O programa abaixo, dado um nmero n, escreve-o na base 2, porm os dgitos saem na ordem inversa. Veja a sada.
#include <stdio.h> /* dado n>=0 escrever n na base 2 os dgitos vo sair ao contrrio */ int main() { int n; /* ler o n */ printf("digite o valor de n:"); scanf("%d", &n); /* imprima o resto e divida n por 2 o nmero binrio vai estar ao contrrio */ while (n > 0) { printf("%1d", n%2); n = n / 2; } } digite o valor de n:76 0011001

O programa abaixo faz a mesma coisa, s que faz com que os dgitos sejam impressos na ordem correta.
#include <stdio.h> /* dado n>=0 escrever n na base 2 */ int main() { int n, d; /* ler o n */ printf("digite o valor de n:"); scanf("%d", &n); /* descubra a potncia de 2 imediatamente superior a n */ d = 1; while (d <= n) d = d * 2; /* retrocede uma vez */ d = d / 2; /* ache o quociente pelas potncias de 2 sucessivas */ while (d > 0) { printf("%1d", n / d); n = n % d; d = d / 2; } }
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

digite o valor de n:125 1111101

Representao interna de nmeros binrios J vimos acima que variveis do tipo char ocupam 8 bits, short 16 bits, int 32 bits e long int 64 bits. Assim, supondo:
unsigned unsigned unsigned unsigned char a = 1; short b = 2; int c = 3; long int d = 4;

Teriam a seguinte representao interna:


a 00000001 b 00000000 00000010 c 00000000 00000000 00000000 00000011 d 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000100

Notao complemento de 2 para a representao de nmeros negativos Os nmeros negativos so representados internamente numa notao denominada complemento de 2. Uma primeira idia para se representar nmeros negativos, seria reservar o bit mais da esquerda para o sinal. Assim em um char (8 bits) poderamos representar os nmeros 127 a +127 (255 possveis), isto , em binrio 11111111 e 01111111. O zero possui 2 representaes: 00000000 e 10000000. A notao complemento de 2, permite armazenar um valor a mais (de 128 a +127, ou seja, 256 possveis), alm de outras facilidades que veremos abaixo. Vejamos um exemplo para uma palavra de 4 bits apenas, para ficar mais fcil. Os valores representveis sero:
-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2 ,3 ,4, 5, 6, 7 Valor -8 -7 -6 -5 -4 -3 -2 -1 0 Bits 1000 1001 1010 1011 1100 1101 1110 1111 0000

MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

1 2 3 4 5 6 7

0001 0010 0011 0100 0101 0110 0111

Para se obtermos o tal complemento de 2 de um nmero negativo, basta pegar o padro de bits correspondente ao positivo, invertermos todos os bits (zeros por uns e vice-versa) e somar um em binrio. Como a tabela acima cclica, somas e subtraes so somas e correspondem a deslocar-se na tabela. Por exemplo: 2 4 2 + (-4), ou 0010 + 1100 = 1110, ou seja 2 (veja a tabela). Outro efeito, dessa notao quando os valores passam dos limites. Por exemplo:
7+2 = -7 5+5 = -6

Portanto, cuidado quando usar um char com sinal (no unsigned), para fazer operaes aritmticas e o resultado eventualmente no couber em um char. Se quiser armazenar valores maiores o iguais a 128=27, use unsigned char. O mesmo ocorre com short (maiores ou iguais a 215) e int (valores maiores ou iguais a 231). O que ser impresso pelo programa abaixo? #include <stdio.h> #include <stdlib.h> int main() { char a=150; unsigned char b=150; printf("a=%d;b=%d",a,b); system("PAUSE"); return 0; } a=-106;b=150 E pelo programa abaixo? #include <stdio.h> #include <stdlib.h> int main() { char a=120;
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

unsigned b=120; char i=0; while (i++<20) printf("\na=%d;b=%d",a++,b++); system("PAUSE"); return 0; } a=120;b=120 a=121;b=121 a=122;b=122 a=123;b=123 a=124;b=124 a=125;b=125 a=126;b=126 a=127;b=127 a=-128;b=128 a=-127;b=129 a=-126;b=130 a=-125;b=131 a=-124;b=132 a=-123;b=133 a=-122;b=134 a=-121;b=135 a=-120;b=136 a=-119;b=137 a=-118;b=138 a=-117;b=139 Constantes inteiras decimais, octais e hexadecimais em c Em C, as constantes inteiras podem ser escritas nas bases decimal, octal ou hexadecimal: Exemplos:
Decimal 0 1 2 3 4 5 7 8 10 20 32 63 100 Octal (iniciada por 0) 00 01 02 03 04 05 07 010 012 024 040 077 0144 Hexadecimal (iniciada por 0x ou 0X) 0x0 0x1 0x2 0x3 0x4 0x5 0x7 0x8 0xa ou 0XA 0x14 0x20 0x3f ou 0X3F 0x64

MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

127 128 255

0177 0200 0377

0x7f ou 0X7F 0x80 0xff ou 0XFF

Exemplos de comandos:
int x; x = 0xff; for (x = 077; x < 0777; x++) ... if (x == 0xfa) .....

Alm disso, as constantes inteiras podem ter sufixo L para torn-las long, ou U para tornlas unsigned como nos exemplos abaixo:
1L constante 1 decimal long 1U constante 1 decimal unsigned 1UL constante 1 decimal unsigned long 0177L constante 0177 octal long 0x2abUL constante 2ab hexadecimal unsigned long

Operaes com bits So os seguintes os operadores que manipulam bits: a) b) c) d) e) f) Deslocamento para a esquerda (shift left) << Deslocamento para a direira (shift left) << E lgico (and) & OU lgico (or) | OU exclusivo (xor) ^ NO lgico ou o complemento (not) ~

Exemplos supondo:
unsigned char a = 1, b = 255, c; // observe que em binrio a=00000001 e b=11111111 c = a << 2; //desloca a 2 bits para a esquerda, portanto c fica com 4 c = b >> 3; //desloca c 3 bits para a direita, portanto c fica com 31 c = a&b; // c fica com 1 c = a|b; // c fica com 255 c = a^b; // c fica com 254

Os operadores aplicam-se a todos os tipos numricos e inteiros (char, short, int, long int, signed ou unsigned) e opera bit a bit. Veja o programa abaixo e o que ser impresso:
#include <stdio.h> int main() {
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

unsigned char a=1, b=255, c, d, i; /* observe que a = 00000001 ou a = 01h b = 11111111 ou b = ffh */ for (i = 0; i < 9; i++) { c = a << i; d = b >> i; printf("\na deslocado %1d bits para esquerda = %5u", i, c); printf("\nb deslocado %1d bits para direita = %5u", i, d); } } a b a b a b a b a b a b a b a b a b deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado deslocado 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 bits bits bits bits bits bits bits bits bits bits bits bits bits bits bits bits bits bits para para para para para para para para para para para para para para para para para para esquerda direita esquerda direita esquerda direita esquerda direita esquerda direita esquerda direita esquerda direita esquerda direita esquerda direita = = = = = = = = = = = = = = = = = = 1 255 2 127 4 63 8 31 16 15 32 7 64 3 128 1 0 0

Idem para o programa abaixo:


int main() { unsigned char a=1, b=255, i; /* observe que a = 00000001 ou a = 01h b = 11111111 ou b = ffh */ for (i = 0; i < 9; i++) { printf("\na - decimal = %5u - hexadecimal = %2x" "\nb - decimal = %5u - hexadecimal = %2x" "\na&b - decimal = %5u - hexadecimal = %2x" "\na|b - decimal = %5u - hexadecimal = %2x" "\na^b - decimal = %5u - hexadecimal = %2x" "\n~a - decimal = %5u - hexadecimal = %2x\n", a, a, b, b, a&b, a&b, a|b, a|b, a^b, a^b, (unsigned char)(~a), (unsigned char)(~a)); a = a << 1;
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

b = b >> 1; } } a b a&b a|b a^b ~a a b a&b a|b a^b ~a a b a&b a|b a^b ~a a b a&b a|b a^b ~a a b a&b a|b a^b ~a a b a&b a|b a^b ~a a b a&b a|b a^b ~a decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 1 255 1 255 254 254 2 127 2 127 125 253 4 63 4 63 59 251 8 31 8 31 23 247 16 15 0 31 31 239 32 7 0 39 39 223 64 3 0 67 67 191 hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = 1 ff 1 ff fe fe 2 7f 2 7f 7d fd 4 3f 4 3f 3b fb 8 1f 8 1f 17 f7 10 f 0 1f 1f ef 20 7 0 27 27 df 40 3 0 43 43 bf

MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

a b a&b a|b a^b ~a a b a&b a|b a^b ~a

decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal

= = = = = = = = = = = =

128 1 0 129 129 127 0 0 0 0 0 255

hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal hexadecimal

= = = = = =

80 1 0 81 81 7f

= 0 = 0 = 0 = 0 = 0 = ff

Veja agora outro programa que escreve os nmeros de 0 a n na base 2. Veja tambm o que ser impresso:
#include <stdio.h> #include <stdlib.h> int main() { int i, j, k, n; printf("entre com n:"); scanf("%d", &n); n = abs(n); /* considere positivo */ for (i = 1; i <= n; i++) { k = i; printf("\n%d - ",k); /* ache a potencia de 2 imediatamente maior que i */ for (j = 0; ; j++) if (k < (1 << j)) break; /* portanto, i < 2**j */ j--; while (j >= 0) { /* imprime n dividido por 2**j */ printf("%1d", k / (1 << j)); k = k % (1 << j); j--; } } } entre com n:15 1 - 1 2 - 10 3 - 11 4 - 100 5 - 101 6 - 110 7 - 111 8 - 1000 9 - 1001 10 - 1010
MAC 122 PDA Marcilio Revisado 11Ago10

MAC 122 PDA Marcilio Revisado 11Ago10

11 12 13 14 15

1011 1100 1101 1110 1111

Exerccio refaa os comandos abaixo, usando operaes >> e << em vez de * e /


x x x x x x = = = = = = x x x x x x * * * / / * 2; 4; 32; 2; 16; 6;

Nos exemplos abaixo, supor que os bits dentro de uma varivel esto numerados da direita para a esquerda, isto : tipo char b7, b6, b5, b4, b3, b2, b1, b0 tipo short b15, b14, b13, ..., b2, b1, b0 tipo int b31, b30, b29, ..., b2, b1, b0 uma maneira conveniente de numerar, pois o nmero do bit coincide com a potncia de 2 da base binria.
unsigned char x; int b; /* if if if /* if if if verificar se o bit 5 de x 1 */ (x & 32 != 0); (x & 040 != 0); /* outra forma */ (x & 0x20 != 0); /* outra forma */ verificar se ambos os bits 0 e 7 de x so 1 */ (x & 129 != 0); (x & 0201 != 0); /* outra forma */ (x & 0x81 != 0); /* outra forma */

/* fazer com que o bit 5 de x fique 1 */ x = x | 32; x = x | 040; /* outra forma */ x = x | 0x20; /* outra forma */

MAC 122 PDA Marcilio Revisado 11Ago10