7 Operadores e Expressões 7.1 Definição de operador, expressão e operando Um operador é um símbolo utilizado para identificar que uma determinada operação deve ser realizada sobre um ou mais parâmetros, denominados operandos. Já uma expressão pode ser considerada um conjunto de operações efetuadas sobre certos dados a fim de obter um resultado. Um operando pode ser um valor escalar ou uma expressão. 7.2 Tipos de operadores Cada linguagem possui seu próprio conjunto de operadores definidos, os quais podem ser aplicados sobre determinados tipos de dados e conseguir resultados distintos. Em C, podemos agrupar os operadores em aritméticos, relacionais, lógicos e de atribuição. Estes não são, entretanto, os únicos tipos de operadores existentes em C há também o operador sizeof() (que estudaremos neste capítulo) e o operador?, que estudaremos no próximo capítulo 7.2.1 Operadores aritméticos São operadores geralmente empregados sobre dados numéricos, utilizados para algum tipo de cálculo aritmético. A tabela abaixo apresenta os principais operadores aritméticos em C: Operador Significado + Adição ++ Incremento - Subtração ou inversão de sinal -- Decremento * Multiplicação
/ Divisão % Resto da divisão inteira Exemplo: int x = 0; int y = 0; int a, b; int c = 2 * ( 3 + 4 ); /*Declarando uma variável c cujo valor inicial é o produto de 2 com a soma de 3 e 4; */ a = ++x ; //Incremente x e então retorne o seu valor, a será 1 e x será 1 b = y++; //Retorne o valor de y e então o incremente, b será 0 e y será 1 Quando programando em qualquer linguagem, deve-se ter cuidado quanto à precedência de certos operadores sobre outros, isto é, sobre quais operadores devem ser aplicados primeiros: Um operador que possua uma maior precedência será executado antes de um operador que possua menor precedência; Quando dois operadores com mesma precedência fazem parte da mesma expressão, o operador mais à esquerda é avaliado primeiro; Parênteses podem ser utilizados para alterar a ordem de execução das expressões, já que eles possuem maior precedência. Na tabela abaixo, uma apresentação da ordem de precedência dos operadores aritméticos aqui listados: Precedência Operador Maior ++ -- - (unário) Menor + - * / % Para alguns operadores, os tipos dos operandos podem influenciar como os mesmos serão avaliados. Por exemplo, no caso da divisão, caso os operandos sejam do tipo inteiro, será realizada uma divisão inteira, não retornando, portanto, a parte decimal. Já com a operação de módulos, não são admitidos operadores de algum tipo com ponto flutuante (float ou double). São necessárias, então, algumas conversões dos dados antes de realizar tal tipo de operação.
7.2.2 Operadores relacionais São operadores geralmente empregados na comparação (de igualdade ou desigualdade) entre dois valores escalares. A tabela abaixo apresenta os principais operadores relacionais em C: Operador Significado = = Igual a > Maior do que >= Maior ou igual a < Menor do que <= Menor ou igual a!= Diferente de Tais operadores podem ser empregados na comparação de inteiros, reais e caracteres! 7.2.3 Operadores lógicos São operadores geralmente utilizados para cálculo lógico ou bit a bit entre um ou dois operandos. Vale lembrar que em C não há um tipo de dado booleano, sendo então empregado o valor numérico zero para representar falso e qualquer outro valor diferente de zero para representar verdadeiro. Sendo assim, sempre que uma expressão retornar falso ela estará retornando, na verdade, zero, e caso retorne verdadeiro estará retornando 1 ou outro valor. A tabela abaixo apresenta os principais operadores aritméticos em C: Operador Significado! Negação (NOT). Caso o operando passado seja verdadeiro, o resultado será falso, caso contrário, o resultado será verdadeiro. && & Conjunção (AND). Retornará verdadeiro se ambos os operandos forem verdadeiros. Trabalha por meio de curto-circuito (shortcircuit), ou seja, assim que um operando retornar falso, não mais avaliará os demais operandos e retornará falso. Conjunção bit a bit (AND). Executará o AND em nível de bit (para
cada par de bits de cada operando, retornará o bit 1 se ambos tiverem valor 1 e 0 caso contrário). Trabalha avaliação completa, ou seja, mesmo que um operando já tenha retornado falso, continuará a avaliar os demais operandos e retornará falso. Disjunção (OR). Retornará verdadeiro se um dos operandos for verdadeiro. Trabalha por meio de curto-circuito (short-circuit), ou seja, assim que um operando retornar verdadeiro, não mais avaliará os demais operandos e retornará verdadeiro. Disjunção bit a bit (OR). Executará o OR em nível de bit (para cada par de bits de cada operando, retornará o bit 1 se um deles tiver o valor 1 e 0 caso contrário). Trabalha por meio de avaliação completa, ou seja, mesmo que um operando já tenha retornado verdadeiro, continuará a avaliar os demais operandos e retornará verdadeiro. ^ Disjunção Exclusiva (XOR). Executa o XOR (OU exclusivo) tanto lógico quanto em nível de bit (para cada par de bits de cada operando, retornará o bit 1 se um deles tiver o valor 1 e o outro tiver o valor 0 e 0 caso contrário). Como se pode perceber, alguns operadores possuem finalidades similares, porém com algumas diferenças que são fundamentais, como o fato de trabalhar como curtocircuito (short-circuit) ou avaliação completa (long-circuit). Entretanto, é importante tomar cuidado, pois o resultado de certas operações lógicas podem ser bastante distintas, mesmo quando realizadas por operadores aparentemente similares. Por exemplo, o resultado de ( 4 && 2 ) é 1, isto é, verdadeiro, entretanto ( 4 & 2 ) é 0, logo seria considerado falso. 7.2.4 Operadores de atribuição O operador de atribuição fundamental em C é o =, utilizado sempre que atribuir um valor a uma variável é necessário. Entretanto, é possível utilizar-se de algumas formas derivadas do mesmo para realizar não somente a atribuição, mas também algum outro tipo de operação sobre os dados. A esses operadores denominamos operadores de atribuição composta. Operadores de atribuição composta Em C, qualquer instrução que possua a forma: <variavel> = <variavel> <operador> <expressao>; Pode ser escrita como:
<variavel> <operador>= <expressao>; Isso quer dizer que se temos uma variável qualquer no lado esquerdo da atribuição e a mesma é o primeiro operando de um dado operador do lado direito, podemos combinar o operador da expressão e o operador de atribuição, conseguindo assim reescrever a instrução de forma mais curta. Abaixo, uma tabela contendo alguns exemplos: Atribuição composta Forma equivalente a += b; a = a + b; a -= b; a = a b; a *= b; a = a * b; a /= b; a = a / b; a %= b; a = a % b; 7.2.5 Operador sizeof() Este operador unário é empregado quando se deseja saber o tamanho em bytes de uma determinada variável, expressão ou tipo. Quando se verificando o tamanho de uma variável ou expressão, não é necessário o uso de parênteses, comportando-se igual a todos os outros operadores. Exemplo: sizeof x. Entretanto, se estamos a aplicar tal operador sobre um tipo de dado, então precisamos utilizar parênteses, em uma notação igual à de uma função. Exemplo: sizeof(float).
7.3 Exercícios 1. Escreva na linguagem C as seguintes expressões: a) b) c) d) z está entre x + 2 e x + 7, inclusive e) x ou y é negativo, mas não os dois! Obs: Pode-se empregar a função pow(x, y) da biblioteca math.h a fim de realizar cálculos de potenciação, onde x y = pow(x, y).