notas-de-aula- Schneider
29 pág.

notas-de-aula- Schneider


DisciplinaProgramação I21.840 materiais250.149 seguidores
Pré-visualização11 páginas
não têm relação com o 
espaço ocupado em memória pelos tipos envolvidos. A definição dessa classificação não é precisa, 
assim, nem sempre é conveniente classificar determinada conversão em uma dessas categorias.
Podem ser explícitas ou implícitas. Às vezes, o termo coerção é usado somente para as conversões 
implícitas. O autor deste texto usa a palavra coerção como sinônimo de conversão.
A maioria das linguagens oferece instruções para conversão de tipos, que podem ser apresentadas 
prof. Bruno Schneider 11
Notas de Aula de GCC105 - BCC e BSI - UFLA
como elementos sintáticos da linguagem ou na forma de funções.
2.3.3.1 Coerção em expressões
Se uma linguagem permite expressões aritméticas com operadores que usam operandos de tipos 
diferentes (expressões de modo misto), devem definir conversões implícitas.
Em muitas linguagens as conversões implícitas de estreitamento causam a emissão de avisos por 
parte do compilador.
Não existe um consenso a respeito do que é melhor: restringir a flexibilidade das expressões ou 
deixar a verificação de tipos sob a responsabilidade do programador.
As coerções de subfaixas de inteiros para inteiros, ou de inteiros pequenos para inteiros são muito 
comuns.
Coerções mais profundas como a conversão de strings em valores numéricos são mais comuns em 
linguagens com vinculação dinâmica de tipos.
2.3.4 Operadores relacionais e expressões booleanas
Linguagens oferecem operadores relacionais para construir expressões booleanas. Operadores 
relacionais retornam um valor do tipo booleano (se ele for um tipo da linguagem).
Operadores relacionais costumam estar disponíveis para tipos numéricos, strings e ordinais 
(enumerados e subfaixas).
Expressões booleanas são aquelas que retornam um tipo booleano (o operador mais externo é 
relacional).
Um efeito interessante da falta do tipo booleano na linguagem C é validade da expressão (a > b > c) 
que não tem o mesmo significado que se espera pela notação matemática.
2.3.5 Avaliação em curto-circuito
Muitas vezes, para se determinar o valor de uma expressão, não é preciso avaliar todos os 
operadores dela. Quando a avaliação de expressões é feita levando em conta esses casos especiais, 
ela é dita uma avaliação em curto-circuito.
A avaliação em curto-circuito é incomum para expressões aritméticas, mas é comum para 
expressões booleanas.
Na avaliação em curto-circuito, funções que mudam o estado de algo e retornam valor podem não 
ser chamadas, não causando qualquer mudança de estado. Por outro lado, nas avaliações em circuito 
longo, operações ilegais podem ser executadas caso o programador esperasse ver apenas uma parte 
da expressão processada.
Algumas linguagens tem operadores específicos para os dois tipos de avaliação (ex.: and then/or 
eles de Ada). Usar operadores lógicos bit a bit pode prover flexibilidade (ex.: & e | no C, C++ e 
Java).
2.3.6 Operador de atribuição
A atribuição é a instrução que realiza cópia de valores de um armazenamento para outro. É uma das 
características básicas da programação imperativa pois possibilita a alteração do estado de um 
prof. Bruno Schneider 12
Notas de Aula de GCC105 - BCC e BSI - UFLA
processamento.
Uma atribuição envolve dois elementos: 
\u2022 uma expressão cujo valor pode ser encontrado, chamada de right value (valor direito) já que 
costuma aparecer do lado direito da atribuição nas várias regras de sintaxe e
\u2022 uma expressão cujo armazenamento pode ser encontrado, chamada de left value (valor 
esquerdo).
Frequentemente as linguagens têm regras sintáticas que impedem elementos como constantes 
(literais ou não) e expressões aritméticas (variáveis temporárias) de serem usadas onde se espera um 
left value.
2.3.6.1 Atribuição simples
É a forma tradicional, em que uma variável recebe o valor de uma expressão. O operador pode 
retornar algo ou não.
2.3.6.2 Alvos múltiplos
Várias variáveis recebem o valor de uma expressão. Esse efeito pode ser imitado pelos operadores 
que retornam referências.
2.3.6.3 Alvos condicionais
Usando o operador ternário ?:, C++ e Java permitem alvos condicionais.
2.3.6.4 Atribuição composta
É a atribuição usando expressões em que a variável modificada faz parte da expressão (ex.: += em 
C, C++ e Java).
2.3.6.5 Operador unário de atribuição
Incrementam e decrementam, como nas linguagens C, C++ e Java.
2.3.6.6 Atribuição como função
O operador de atribuição pode retornar valor como em C, C++ e Java.
Facilitam a atribuições seguidas de teste. Permitem imitar os alvos múltiplos. Reduzem a 
legibilidade e, na falta do tipo booleano, reduzem a capacidade do compilador para detectar erros.
Java não tem o problema das atribuições no meio de expressões (de C e C++) porque tem o tipo 
booleano e o uso de número em lugar de booleanos causa erros de tipo.
2.3.7 Atribuição de modo misto
As linguagens podem permitir atribuição do valor de um tipo à uma variável de outro tipo. Pode-se 
usar coerção.
prof. Bruno Schneider 13
Notas de Aula de GCC105 - BCC e BSI - UFLA
2.4 Controle de fluxo
O controle de fluxo é a determinação da ordem de execução das instruções de um programa. As 
regras de precedência e associatividade de operadores, vistas na seção 2.3.1, são uma forma de 
controle de fluxo. As linguagens também precisam prover formas de controlar o fluxo entre os 
vários blocos de programa.
O controle de fluxo é tão fundamental nos programas imperativos quanto a atribuição. Mecanismos 
de seleção de instruções permitem produzir repetições ou escolher entre várias formas de computar 
um valor.
Duas formas de controle (o desvio condicional/incondicional) são necessárias. Duas formas são 
recomendadas: o desvio condicional e a repetição com teste no início. As linguagens proporcionam 
mais formas, porém não muitas, para que não fiquem complicadas demais.
As instruções de controle devem ter entrada única e saída única. As entradas múltiplas são perigosas 
enquanto que as saídas múltiplas apenas reduzem a legibilidade.
2.4.1 Instruções compostas
São blocos de instruções tratados como se fossem uma única instrução. Eliminam a necessidade de 
instruções delimitadas e são especialmente interessantes para as estruturas de controle de fluxo. 
Também auxiliam a manter uma \u201clógica positiva\u201d, que destaca os casos especiais.
Algumas linguagens exigem que instruções compostas apareçam em determinados contextos.
Quase sempre, as instruções compostas são demarcas por algum elemento sintático (ex.: begin/end), 
porém algumas linguagens modernas usam a endentação para demarcação.
2.4.2 Instruções de seleção
Permitem escolher caminhos de execução.
Do ponto de vista do hardware, geralmente existem dois tipos de instrução de controle de fluxo: 
desvio condicional e incondicional. Esses dois elementos podem ser combinados em instruções de 
seleção mais abstratas. As linguagens procuram esconder o desvio incondicional do programador, 
oferecendo seletores.
2.4.2.1 Seleção unidirecional e bidirecional
O seletor unidirecional \u201cif (teste) instrução\u201d é uma abstração quase direta do desvio condicional do 
hardware.
Para desincentivar o uso de desvio incondicional, as linguagens oferecem instruções compostas ou 
algum tipo de marcador para o final das instruções.
O seletor bidirecional \u201cif (teste) then instrução else instrução\u201d é o principal seletor em todas as 
linguagens. Geralmente o seletor unidirecional incorpora algum elemento sintático (como o \u201cthen\u201d) 
de forma a se tornar uma versão especial do seletor bidirecional.
O teste é quase sempre uma expressão booleana.
prof. Bruno Schneider 14
Notas de Aula de GCC105 - BCC e BSI - UFLA
2.4.2.2 Seletores aninhados
Quando uma instrução de seleção pode ser aninhada em outra, podemos ter ambiguidade. Essa 
ambiguidade pode ser resolvida por:
\u2022 uma regra da linguagem (ex.: Pascal/C++ - o else é sempre vinculado ao if mais recente);
\u2022 sintaxe da linguagem (ex.: Algol60 - o if não pode ser usado como instrução