Buscar

Biblioteca_1792705

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 243 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 243 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 243 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

PARADIGMAS DE LINGUAGENS
DE PROGRAMAÇÃO
Professor Alessandro Larangeiras
 
UNIDADE 1: CONCEITOS PRELIMINARES
1.1 Razões para estudar conceitos de linguagens de programação 
1.2 Domínios de programação
1.3 Critérios de avaliação de linguagens
1.4 Influências no projeto de linguagens
1.5 Categorias de linguagens
1.6 Trade-offs no projeto de linguagens 
1.7 Métodos de implementação
1.8 Ambientes de programação
CONTEÚDO
 
UNIDADE 2: NOMES, VINCULAÇÕES E ESCOPO
2.1 Nomes
2.2 Variáveis
2.3 O conceito de vinculação
2.4 Escopo
2.5 Escopo e tempo de vida
2.6 Ambientes de referenciamento
2.7 Constantes nomeadas
UNIDADE 3: TIPOS DE DADOS
3.1 Tipos de dados primitivos
3.2 Cadeias de Caracteres, Tipos enumeração, Tipos de Matrizes, Matrizes 
associativas, Registros, Tuplas, Listas, Uniões, Ponteiros e referências, 
Verificação de tipos, Teoria e tipos de dados
3.3 Dados abstratos e encapsulamento
CONTEÚDO
 
 UNIDADE 4: EXPRESSÕES E SENTENÇAS DE ATRIBUIÇÃO
4.1 Introdução 
4.2 Expressões aritméticas 
4.3 Operadores sobrecarregados 
4.4 Conversões de tipos 
4.5 Expressões relacionais e booleanas 
4.6 Avaliação em curto-circuito 
4.7 Sentenças de atribuição 
4.8 Atribuição de modo misto
UNIDADE 5: SUBPROGRAMAS
5.1 Introdução 
5.2 Fundamentos dos subprogramas 
5.3 Questões de projeto para subprogramas 
5.4 Ambientes de referenciamento local 
5.5 Métodos de passagem de parâmetros
CONTEÚDO
 
UNIDADE 6: IMPLEMENTAÇÃO DE SUBPROGRAMAS
6.1 A semântica geral de chamadas e retornos
6.2 Implementação de subprogramas simples
UNIDADE 7: SUPORTE A PROGRAMAÇÃO ORIENTADA A OBJETOS
7.1 Introdução
7.2 Programação orientada a objetos
7.3 Questões de projeto para linguagens orientada as objeto
7.4 Suporte para programação orientada a objetos em linguagens específicas
7.5 Implementação de construções orientadas a objetos
CONTEÚDO
 
UNIDADE 8: CONCORRÊNCIA
8.1 Introdução
8.2 Introdução à concorrência em nível de subprograma
8.3 Semáforos
8.4 Monitores
8.5 Passagem de mensagem
8.6 Linha de execução em Java e em C#
UNIDADE 9: TRATAMENTO DE EXCEÇÕES E TRATAMENTO DE EVENTOS
9.1 Introdução ao tratamento de exceções
9.2 Tratamento de exceções em C++, Java e Python
9.3 Introdução ao tratamento de eventos
9.4 Tratamento de Eventos em Java e C#
CONTEÚDO
 
RAZÕES PARA ESTUDAR
CONCEITOS DE LINGUAGENS
DE PROGRAMAÇÃO 
 
✓Aumento da capacidade 
de expressar ideias, com 
lógica e sistematização 
(SEBESTA, 2018, p. 2-32).
 
 
// RECEITA DE BOLO SIMPLES NA FORMA DE ALGORITMO.
// Reserve os ingredientes.
acucar = 2 xícaras de chá de açúcar;
farinhaDeTrigo = 3 xícaras de chá de farinha de trigo;
margarina = 4 colheres de sopa de margarina;
sacoDeOvos = 3 ovos;
leite = 1 e 1/2 xícara de chá de leite;
fermento = 1 colher de sopa de fermento em pó;
formaDeBolo = VAZIO;
// Separe claras e gemas.
PARA CADA ovo DO sacoDeOvos FAÇA
claras = claras + pegaClara(ovo);
gemas = gemas + pegaGema(ovo);
// Bata as claras em neve e reserve.
clarasEmNeve = bateClarasEmNeve(claras);
// Misture as gemas, a margarina e o açúcar até obter uma massa homogênea.
massa = gemas + margarina + acucar;
PARA contagem = 1; ENQUANTO contagem <= 5; FAÇA
mistura(massa);
// Acrescente o leite e a farinha de trigo aos poucos, sem parar de bater.
PARA contagem = 1; ENQUANTO contagem <= 4; FAÇA
bate(massa, (leite /4), (farinhaDeTrigo /4));
// Adicione as claras em neve e o fermento.
bate(massa, clarasEmNeve, fermento);
// Despeje a massa em uma forma grande de furo central untada e enfarinhada.
unta(formaDeBolo);
enfarinha(formaDeBolo);
formaDeBolo = massa;
// Asse em forno médio, 180°C, preaquecido, por aproximadamente 40 minutos.
assa(formaDeBolo, MEDIO, 180, PREAQUECIDO, 40);
 
✓Escolha da linguagem mais adequada ao projeto, 
com base em suas virtudes e fraquezas (SEBESTA, 
2018, p. 2-32).
 
✓Aumento da habilidade de aprender novas 
linguagens, a partir dos conceitos e recursos das já 
conhecidas (SEBESTA, 2018, p. 2-32).
 
✓Melhor entendimento da importância 
que tem os detalhes de implementação 
adotados em uma linguagem no uso 
mais inteligente desta linguagem e na 
identificação e correção de certos 
erros presentes em programas 
escritos com esta linguagem (SEBESTA, 
2018, p. 2-32).
 
✓Melhor emprego de linguagens já conhecidas, 
devido à possibilidade de explorar toda a sua 
extensão, complexidade e recursos (SEBESTA, 
2018, p. 2-32).
 
✓Avanço geral da computação, quanto à 
popularidade e à adesão dos recursos 
das linguagens (SEBESTA, 2018, p. 2-32).
 
DOMÍNIOS DE 
PROGRAMAÇÃO
 
Os computadores são utilizados em uma infinidade de 
tarefas, desde controlar usinas nucleares até disponibilizar 
jogos eletrônicos em telefones celulares. Por causa dessa 
diversidade de uso, linguagens de programação com 
objetivos muito diferentes foram desenvolvidas.
SEBESTA, 2018, p. 5.
 
Aplicações científicas. Os primeiros computadores digitais, surgidos 
no final dos anos 1940, início dos anos 1950, foram desenvolvidos e 
usados para aplicações científicas.
Normalmente, as aplicações científicas daquela época utilizavam 
estruturas de dados relativamente simples, mas exigiam diversos 
cálculos aritméticos de ponto flutuante. As estruturas de dados mais 
comuns eram os vetores e as matrizes; as estruturas de controle 
mais comuns eram os laços de contagem e as seleções. As primeiras 
linguagens de programação de alto nível inventadas para aplicações 
científicas foram projetadas para suprir tais necessidades. [...] A 
primeira linguagem para aplicações científicas foi FORTRAN. ALGOL 
60 e a maioria de seus descendentes também tinham a intenção de 
serem usados nessa área, apesar de terem sido projetados também 
em áreas relacionadas.
Para aplicações científicas nas quais a eficiência é a principal 
preocupação, como as que eram comuns nos anos 1950 e 1960, 
nenhuma linguagem subsequente é significativamente melhor que 
Fortran, o que explica por que ela ainda é usada.
SEBESTA, 2018, p. 5.
 
Aplicações empresariais. O uso de computadores para aplicações 
comerciais começou nos anos 1950. Computadores especiais 
foram desenvolvidos para esse propósito, com linguagens 
especiais. A primeira linguagem de alto nível para negócios a 
ser bem-sucedida foi o COBOL [...], com sua primeira versão 
aparecendo em 1960. COBOL provavelmente ainda é a 
linguagem mais utilizada para tais aplicações. Linguagens de 
negócios são caracterizadas por facilidades para a produção de 
relatórios elaborados, maneiras precisas de descrever e 
armazenar números decimais e caracteres, e a habilidade de 
especificar operações aritméticas decimais.
SEBESTA, 2018, p. 5-6.
 
Inteligência artificial. A Inteligência Artificial (IA) é uma ampla 
área de aplicações computacionais caracterizadas pelo uso de 
computações simbólicas em vez de numéricas. Computações 
simbólicas são aquelas nas quais símbolos, compostos de nomes 
em vez de números, são manipulados. Além disso, a computação 
simbólica é feita de modo mais fácil por meio de listas ligadas de 
dados do que por meio de vetores. Esse tipo de programação 
algumas vezes requer mais flexibilidade do que outros domínios 
de programação [...].
A primeira linguagem de programação amplamente utilizada, 
desenvolvida para aplicações de IA, foi a linguagem funcional 
Lisp [...], que apareceu em 1959. A maioria das aplicações de IA 
desenvolvidas antes de 1990 foi escrita em Lisp ou em um de 
seus parentes próximos. No início dos anos 1970, entretanto, 
uma abordagem alternativa a algumas dessas aplicações 
apareceu – programação lógica usando a linguagem Prolog [...]. 
Mais recentemente, algumas aplicações de IA foram escritas em 
linguagens de sistemas como C, Scheme [...] (um dialeto de Lisp), 
e PROLOG [...].
SEBESTA, 2018, p. 6.
 
Software para a Web. A World Wide Web é mantida por uma 
eclética coleção de linguagens, que vão desde linguagens de 
marcação, como HTML, que não é de programação, até 
linguagens deprogramação de propósito geral, como Java. 
Dada a necessidade universal de conteúdo dinâmico na Web, 
alguma capacidade de computação geralmente é incluída na 
tecnologia de apresentação de conteúdo. Essa funcionalidade 
pode ser fornecida por código de programação embarcado em 
um documento HTML. Tal código é normalmente escrito com 
uma linguagem de scripting, como JavaScript ou PHP [...].
SEBESTA, 2018, p. 6.
 
CRITÉRIOS DE AVALIAÇÃO 
DE LINGUAGENS
 
LEGIBILIDADE: facilidade com que códigos fonte podem ser lidos e entendidos. 
Deve ser considerada no contexto do domínio do problema.
✓Simplicidade: capacidade de ser simples, com poucos componentes (palavras, 
símbolos e códigos) básicos. “Programadores que precisam usar uma linguagem 
extensa aprendem um subconjunto dessa linguagem e ignoram outros recursos.” 
(SEBESTA, 2018, p. 8);
✓Ortogonalidade: capacidade de combinar entre si, sem restrições, os componentes 
básicos da linguagem para construir estruturas de controle e de dados. “Por 
exemplo, em uma linguagem de programação que suporta ponteiros, deve ser 
possível definir um ponteiro que aponte para qualquer tipo específico nela 
definido. Entretanto, se não for permitido aos ponteiros apontar para vetores, 
muitas estruturas de dados potencialmente úteis [...] não poderão ser definidas.” 
(SEBESTA, 2018, p. 9);
✓Tipos de dados: capacidade de apresentar mecanismos adequados para definir 
tipos e estruturas de dados. “Por exemplo, suponha que um tipo numérico seja 
usado como uma flag porque não existe nenhum tipo booleano na linguagem. Em tal 
linguagem, poderíamos ter uma atribuição como: timeOut = 1. O significado dessa 
sentença não é claro. Em uma linguagem que inclui tipos booleanos, teríamos: 
timeOut = true. O significado dessa sentença é perfeitamente claro.” (SEBESTA, 
2018, p. 11);
✓Projeto da sintaxe: clareza da sintaxe (palavras reservadas adotadas, forma e 
significado das sentenças).
 
FACILIDADE DE ESCRITA: facilidade com que a linguagem pode ser 
usada para criar programas para determinado domínio. Deve ser 
considerada no contexto do domínio do problema.
✓Simplicidade e ortogonalidade: excesso de componentes (palavras, 
símbolos e códigos) pode ocasionar uso incorreto de alguns 
recursos e subutilização de outros; excesso de ortogonalidade pode 
ser prejudicial, pois, se quaisquer combinações de componentes 
básicos forem válidas, erros em programas podem ser gerados;
✓Expressividade: capacidade de expressar mais com menos. “Por 
exemplo, em C, a notação count++ é mais conveniente e menor que 
count = count + 1.” (SEBESTA, 2018, p. 13).
 
CONFIABILIDADE: capacidade de ser confiável, conforme suas especificações em 
todas as condições.
✓Verificação de tipos: capacidade de verificar erros de tipos de dados em um 
programa, em tempo de compilação (mais desejável) e em tempo de execução (mais 
dispendiosa);
✓Tratamento de exceções: capacidade de interceptar erros em tempo de execução, 
tomar medidas corretivas e manter o funcionamento do programa;
✓Apelidos (aliases): possibilidade de ter um ou mais nomes capazes de acessar a mesma 
célula de memória. “A maioria das linguagens permite algum tipo de apelido – por 
exemplo, dois ponteiros (ou referências) configurados para apontar para a mesma 
variável [...].” (SEBESTA, 2018, p. 14);
✓Legibilidade e facilidade de escrita: “Tanto a legibilidade quanto a facilidade de 
escrita influenciam a confiabilidade. Um programa escrito em uma linguagem que não 
suporta maneiras naturais de expressar os algoritmos exigidos necessariamente usará 
estratégias artificiais. É menos provável que estratégias artificiais estejam corretas 
para todas as situações possíveis. Quanto mais fácil é escrever um programa, maior a 
probabilidade de ele estar correto.” (SEBESTA, 2018, p. 15);
CUSTO: custos para treinar equipes, para escrever programas, para compilar 
programas, para executar programas, de implementação (licenciamento, dependência 
de plataforma de hardware específica), de baixa confiabilidade.
 
INFLUÊNCIAS NO PROJETO 
DE LINGUAGENS
 
ARQUITETURA DE COMPUTADORES: “A arquitetura básica dos 
computadores tem um efeito profundo no projeto de linguagens. A 
maioria das linguagens populares dos últimos 60 anos tem sido projetada 
considerando a principal arquitetura de computadores, chamada de 
arquitetura de von Neumann [...]. Elas são chamadas de linguagens 
imperativas [...]. Devido à arquitetura de von Neumann, os recursos 
centrais das linguagens imperativas são as variáveis, que modelam as 
células de memória; as sentenças de atribuição, baseadas na operação de 
envio de dados e instruções (piping); e a forma iterativa de repetição 
nessa arquitetura.” (SEBESTA, 2018, p. 17).
 
METODOLOGIAS DE PROJETO DE PROGRAMAS: O final de 1960 e o início 
de 1970 trouxeram uma pesquisa intensa, iniciada em grande parte pelo 
movimento da programação estruturada, tanto para o desenvolvimento de 
software quanto para o projeto de linguagens de programação. Uma razão 
importante para essa pesquisa foi a mudança do custo de computação do 
hardware para o software, pois os custos de hardware declinavam e os de 
programação aumentavam [...]. As novas metodologias de desenvolvimento 
de software que emergiram como um resultado da pesquisa de 1970 foram 
chamadas de projeto descendente (top-down) e de refinamento passo a passo 
[...]. No final de 1970, iniciou-se uma mudança nas metodologias de projeto de 
programas, da orientação a procedimentos para a orientação a dados. Os 
métodos orientados a dados enfatizam a modelagem de dados, concentrando-
se no uso de tipos abstratos para solucionar problemas. Para que as 
abstrações de dados sejam usadas efetivamente no projeto de sistemas de 
software, elas devem ser suportadas pelas linguagens utilizadas para a 
implementação [...]. O último grande passo na evolução do desenvolvimento 
de software orientado a dados, que começou no início de 1980, é o projeto 
orientado a objetos. As metodologias orientadas a objetos começam com a 
abstração de dados, que encapsula o processamento com os objetos de dados, 
controla o acesso aos dados e também adiciona mecanismos de herança e 
vinculação dinâmica de métodos [...]. (SEBESTA, 2018, p. 19-20).
 
1. Por que é útil para um programador ter alguma experiência no projeto de linguagens, 
mesmo que ele nunca projete uma linguagem de programação?
2. Quais são os principais critérios de avaliação para a adoção de uma linguagem de 
programação?
3. Qual é a desvantagem de ter recursos demais em uma linguagem?
4. Explique com suas palavras a influência que a expressividade tem na facilidade de 
escrita de códigos em uma linguagem.
5. O que significa uma linguagem ser confiável?
EXERCÍCIOS
 
CATEGORIAS DE 
LINGUAGENS
 
[...] Programação IMPERATIVA é um paradigma de programação 
que descreve a computação como ações, enunciados ou 
comandos que mudam o estado (variáveis) de um programa. 
Muito parecido com o comportamento imperativo das linguagens 
naturais que expressam ordens, programas imperativos são uma 
sequência de comandos para o computador executar. O nome do 
paradigma, imperativo, está ligado ao tempo verbal imperativo, 
onde o programador diz ao computador: faça isso, depois isso, 
depois aquilo... Este paradigma de programação se destaca pela 
simplicidade, uma vez que todo ser humano, ao programar, o 
faz imperativamente, baseado na ideia de ações e estados [...].
PROGRAMAÇÃO IMPERATIVA, 2019.
 
[...] Programação FUNCIONAL é um paradigma de programação que trata a 
computação como uma avaliação de funções matemáticas e evita estados 
ou dados mutáveis. Ela enfatiza a aplicação de funções, ao contrário da 
programação imperativa, que enfatiza mudanças no estado do programa.
[...] Na programação funcional parecem faltar diversas construções 
frequentemente [...] consideradas essenciais em linguagens imperativas, 
como C ou Pascal. Por exemplo, numa programação estritamente funcional, 
não há alocaçãoexplícita de memória, nem declaração explícita de 
variáveis. No entanto, essas operações podem ocorrer automaticamente 
quando a função é invocada; a alocação de memória ocorre para criar 
espaço para os parâmetros e para o valor de retorno, e a declaração 
ocorre para copiar os parâmetros dentro deste espaço recém-alocado e para 
copiar o valor de retorno de volta para dentro da função que a chama. 
Ambas as operações podem ocorrer nos pontos de entrada e saída da 
função, então efeitos colaterais no cálculo da função são eliminados [...].
Os laços, outra construção de programação imperativa, estão presentes por 
meio da construção funcional mais geral de recursividade. Funções 
recursivas invocam a si mesmas, permitindo que uma operação seja 
realizada várias vezes. Recursividade em programação funcional pode 
assumir várias formas e é em geral uma técnica mais poderosa que o uso 
de laços. Por essa razão, quase todas as linguagens imperativas também a 
suportam (sendo Fortran 77 e COBOL exceções notáveis).
PROGRAMAÇÃO FUNCIONAL, 2019.
 
Programação LÓGICA é um paradigma de programação que 
faz uso da lógica matemática [...].
A programação lógica é uma ideia que tem sido investigada 
no contexto da inteligência artificial pelo menos desde o 
momento em que John McCarthy (1958) propôs “programas 
para manipular sentenças instrumentais comuns apropriadas 
à linguagem formal (muito provavelmente uma parte do 
cálculo de predicado)”. O programa básico formará conclusões 
imediatas a partir de uma lista de premissas. Essas 
conclusões serão tanto sentenças declarativas quanto 
imperativas. Quando uma sentença imperativa é deduzida, o 
programa toma uma ação correspondente [...].
PROGRAMAÇÃO LÓGICA, 2019.
 
A ORIENTAÇÃO A OBJETOS é uma maneira (paradigma) de se 
pensar e desenvolver programas. Ao desenvolver um programa 
orientado a objeto, você deve pensar em como a situação que o 
programa está automatizando funciona no mundo real, ou 
seja, quais os objetos envolvidos na situação e como eles se 
relacionam.
A partir disso você deve se preocupar em modelar e 
implementar o programa de maneira que ele espelhe a situação 
existente no mundo real, ou seja, deve criar e manipular as 
representações de objetos existentes no mundo real.
CUNHA, 2019, slide 1.
 
TRADE-OFFS NO PROJETO 
DE LINGUAGENS
 
Os critérios de avaliação de linguagens de programação descritos 
[antes] [...] fornecem um modelo para o projeto de linguagens. 
Infelizmente, esse modelo é contraditório. Em seu brilhante artigo 
sobre o projeto de linguagens, Hoare (1973) afirma que “existem 
tantos critérios importantes, mas conflitantes, que sua 
harmonização e satisfação estão entre as principais tarefas de 
engenharia”.
Dois critérios conflitantes são a confiabilidade e o custo de 
execução. Por exemplo, a linguagem Java exige que todas as 
referências aos elementos de um vetor sejam verificadas para 
garantir que os índices estejam em suas faixas válidas. Esse 
passo aumenta muito o custo de execução de programas Java 
que contenham um grande número de referências a elementos de 
vetores. C não exige a verificação da faixa de índices - dessa 
forma, os programas em C executam mais rápido que programas 
semanticamente equivalentes em Java, apesar de estes serem 
mais confiáveis. Os projetistas de Java trocaram eficiência de 
execução por confiabilidade.
SEBESTA, 2018, p. 21.
 
[...] O conflito entre a facilidade de escrita e a legibilidade 
é comum no projeto de linguagens. Os ponteiros de C++ 
podem ser manipulados de diversas maneiras, o que 
possibilita um endereçamento de dados altamente flexível. 
Devido aos potenciais problemas de confiabilidade com o 
uso de ponteiros, eles não foram incluídos em Java.
Exemplos de conflitos entre critérios de projeto e de 
avaliação de linguagens são abundantes; alguns sutis, 
outros óbvios. Logo, é claro que a tarefa de escolher 
construções e recursos ao projetar uma linguagem de 
programação exige muito comprometimento e trade-offs.
SEBESTA, 2018, p. 21.
 
MÉTODOS DE 
IMPLEMENTAÇÃO
 
✓Implementação baseada em COMPILAÇÃO. 
Exemplos: C, C++, Delphi, VB, COBOL.
 
✓Implementação baseada em INTERPRETAÇÃO PURA. 
Exemplos: PHP, JavaScript.
 
✓Implementação HÍBRIDA. 
Exemplos: Java, C#.NET, VB.NET.
 
✓Implementação baseada em PRÉ-PROCESSADOR 
(processamento imediatamente antes da compilação). 
Exemplo: instrução de pré-processador em C.
 
AMBIENTES DE 
PROGRAMAÇÃO
 
Um ambiente de programação é a coleção de ferramentas 
usadas no desenvolvimento de software. Essa coleção pode 
consistir em apenas um SISTEMA DE ARQUIVOS, um 
EDITOR DE TEXTOS, um LIGADOR e um COMPILADOR. Ou 
pode incluir uma grande coleção de ferramentas 
integradas, cada uma acessada por meio de uma interface 
de usuário uniforme [(IDE - Integrated Development 
Environment)]. Neste último caso, o desenvolvimento e a 
manutenção de software são enormemente melhorados.
Logo, as características de uma linguagem de programação 
não são a única medida da capacidade de desenvolvimento 
de um sistema.
SEBESTA, 2018, p. 29.
 
PRÓS do uso de ambientes de programação:
✓Facilidade na escrita do código fonte, com o realce de palavras 
chave e a identificação prematura de erros de sintaxe;
✓Agilidade no desenvolvimento, com o uso de ferramentas.
CONTRAS do uso de ambientes de programação:
✓Dependência dos recursos que facilitam e agilizam o desenvolvimento;
✓Dificuldade de portabilidade, por acoplamento com recursos 
específicos.
 
NOMES OU IDENTIFICADORES
 
Na maioria das linguagens de programação, os nomes têm 
o mesmo formato: uma letra seguida por uma cadeia de 
letras, dígitos e sublinhados (_). Apesar de o uso de 
sublinhados ter sido disseminado nos anos 1970 e 1980, a 
prática é menos popular atualmente. Nas linguagens 
baseadas em C [(C, Objective-C, C++, Java e C#)], eles 
foram, em grande medida, substituídos pela assim chamada 
notação camelo (CamelCase), [por exemplo: MyStack, ou Low 
Camel Case, por exemplo: myStack] [...]. Note que o uso de 
sublinhados e de caixa mista em nomes é uma questão 
de estilo de programação, não de projeto de linguagem.
SEBESTA, 2018, p. 199.
 
Palavras especiais são palavras que compõem a sintaxe de uma 
linguagem de programação. São divididas em:
✓ PALAVRAS-CHAVE: palavras que são especiais somente em 
determinado contexto. Exemplos em Fortran:
INTEGER real // Variável de tipo INTEGER e nome REAL.
REAL integer // Variável de tipo REAL e nome INTEGER.
✓ PALAVRAS RESERVADAS: palavras que são exclusivas da 
sintaxe, ou seja, não podem ser usadas para nomear variáveis. 
Exemplos em Java: abstract, boolean, break, byte, case, catch, 
char, class, const, continue, default, do, double, else etc.
 
VARIÁVEIS
 
✓ Nome ou identificador: rótulo que identifica a variável, ou seja, seu 
nome propriamente dito;
✓ Endereço: endereço da célula de memória no qual a variável está 
armazenada;
✓ Tipo de dado: faixa de valores que a variável pode armazenar e o 
conjunto de operações suportado. O tipo de dado pode ser PRIMITIVO 
(fornecido por padrão pela linguagem, por exemplo, int, char, double, 
boolean) ou DEFINIDO PELO PROGRAMADOR (por exemplo, classes 
orientadas a objeto);
✓ Valor: conteúdo da célula de memória associada à variável, ou seja, 
o dado armazenado na variável. Se subdivide em L-VALUE e R-VALUE. 
Por exemplo, para a expressão a = b + c, a é uma l-value e b + c, uma 
r-value;
✓ Tempo de vida: prazo em que a variável permanece alocada na 
memória, podendo ser GLOBAL (com efeito no trecho completo 
programa) ou LOCAL (com efeito somente em um trecho específico do 
programa);
✓ Escopo: trecho do programa de efeito da variável.
 
 
VINCULAÇÃO (BINDING 
OU LINKING)
 
Vinculação é a associação entre um atributo e uma entidade, como 
entre uma variável e seu tipo ou valor, ou entre uma operação e 
um símbolo. O momento no qual uma vinculação ocorre é 
chamado de TEMPO DE VINCULAÇÃO.A vinculação e os tempos 
de vinculação são conceitos proeminentes na semântica das 
linguagens de programação. As vinculações podem ocorrer em 
tempo de projeto da linguagem, em tempo de implementação da 
linguagem, em tempo de compilação, em tempo de carga, em 
tempo de ligação ou em tempo de execução. Por exemplo, o 
símbolo de asterisco (*) é geralmente ligado à operação de 
multiplicação em tempo de projeto de uma linguagem. Um tipo de 
dados, como int em C, é vinculado a uma faixa de valores 
possíveis em tempo de implementação da linguagem. Em tempo de 
compilação, uma variável em um programa Java é vinculada a 
um tipo de dados em particular. Uma variável pode ser vinculada 
a uma célula de armazenamento quando o programa é carregado 
na memória [(tempo de carga)]. A mesma vinculação não acontece 
até o tempo de execução, em alguns casos, como as variáveis 
declaradas em métodos Java. Uma chamada a um subprograma de 
uma biblioteca [(DLL, em Windows, SO, em Linux)] é vinculada ao 
código do subprograma em tempo de ligação.
SEBESTA, 2018, p. 203.
 
Por exemplo, a execução da expressão A = B + C ocorreria conforme 
a seguinte sequência de vinculação (OLIVETE JÚNIOR, 2019, slide 22):
1. Obtém-se os endereços de memória de A, B e C;
2. Obtém-se os dados dos endereços de memória B e C;
3. Computa-se B + C;
4. Armazena-se o resultado da computação de B + C no endereço de A.
 
Vinculação de atributos a variáveis. Uma vinculação é estática 
se ocorre pela primeira vez ANTES do tempo de execução e 
PERMANECE INALTERADA ao longo da execução do programa. Se 
a vinculação ocorre pela primeira vez DURANTE o tempo de 
execução ou PODE SER MUDADA ao longo do curso da execução 
do programa, é chamada de dinâmica.
SEBESTA, 2018, p. 203.
Vinculações estática (a) e dinâmica (b).
Fonte: PIRKLE, 2013, p. 22
(a) (b)
 
Vinculação de tipos. Antes de uma variável poder ser 
referenciada em um programa, ela deve ser vinculada a um 
tipo de dados. Os dois aspectos importantes dessa vinculação 
são: como o tipo é especificado e quando a vinculação ocorre. 
Os tipos podem ser especificados ESTATICAMENTE por 
alguma forma de declaração explícita ou implícita. [...] Uma 
declaração explícita é uma sentença em um programa 
que lista nomes de variáveis e especifica que elas são de 
certo tipo. Uma declaração implícita é uma forma de 
associar variáveis a tipos por meio de convenções 
padronizadas, em vez de por sentenças de declaração [...].
A maioria das linguagens de programação amplamente 
usadas, que emprega exclusivamente vinculação estática a 
tipos e foram projetadas desde meados dos anos 1960, exige 
declarações explícitas de todas as variáveis (Visual Basic e 
ML são duas exceções).
SEBESTA, 2018, p. 204.
 
Por exemplo:
// Declaração explícita em Java.
int numero;
// Declaração implícita em C# (inferência de tipo).
// Fonte: SEBESTA, 2018, p. 204.
var sum = 0;
var total = 0.0;
var name = “Fred”;
Lembre-se de que essas variáveis 
são tipadas estaticamente – seus 
tipos são fixos durante toda a vida 
da unidade na qual são declaradas. 
(SEBESTA, 2018, p. 204).
 
A vinculação de tipo de variável implícita é feita pelo 
processador da linguagem, por um compilador ou 
interpretador. Existem várias bases diferentes para as 
vinculações implícitas de tipo de variável. A mais simples 
delas é a convenção de atribuição de nomes. Nesse caso, o 
compilador ou o interpretador vincula uma variável a um 
tipo com base na forma sintática do nome da variável.
Apesar de serem uma pequena conveniência para os 
programadores, as declarações implícitas podem ser 
prejudiciais à confiabilidade, pois impedem o processo de 
compilação de detectar alguns erros de programação e de 
digitação.
SEBESTA, 2018, p. 204.
 
Com a vinculação de tipos DINÂMICA, o tipo de 
uma variável não é especificado por uma sentença de 
declaração, nem pode ser determinado pelo nome da 
variável. Em vez disso, a variável é vinculada a um 
tipo quando é atribuído um valor a ela em uma 
sentença de atribuição. Quando a sentença de atribuição 
é executada, a variável que recebe um valor atribuído é 
vinculada ao tipo do valor da expressão no lado direito 
da atribuição. Tal atribuição também pode vincular a 
variável a um endereço e a uma célula de memória, 
pois diferentes valores de tipo podem exigir diferentes 
quantidades de armazenamento. Qualquer variável pode 
receber qualquer valor de tipo. Além disso, o tipo de 
uma variável pode mudar qualquer número de vezes 
durante a execução do programa. É importante perceber 
que o tipo de uma variável, quando é vinculado 
dinamicamente, pode ser temporário.
SEBESTA, 2018, p. 205.
 
Por exemplo:
// Vinculação de tipo dinâmica em PHP.
$nome = 'Joao';
$idade = 50;
$pi = 3.14159265;
$sim = true;
 
As linguagens nas quais os tipos são vinculados dinamicamente 
são drasticamente diferentes daquelas nas quais os tipos são 
vinculados estaticamente. A principal vantagem da vinculação 
dinâmica de variáveis a tipos é que ela oferece maior 
flexibilidade ao programador. Por exemplo, um programa para 
processar dados numéricos em uma linguagem que usa a 
vinculação de tipos dinâmica pode ser escrito como um 
programa genérico; ou seja, ele será capaz de tratar dados de 
quaisquer tipos numéricos. Qualquer tipo de dados informado 
será aceitável, porque a variável na qual os dados serão 
armazenados pode ser vinculada ao tipo correto quando eles 
forem atribuídos às variáveis após a entrada [...].
SEBESTA, 2018, p. 205.
 
Antes de meados dos anos 1990, a maioria das linguagens de 
programação comumente usadas empregava vinculação de tipos 
estática; as principais exceções eram algumas linguagens 
funcionais, como Lisp. Contudo, desde então houve uma 
mudança significativa para linguagens que usam vinculação 
dinâmica de tipos. Em Python, Ruby, JavaScript e PHP, a 
vinculação de tipos é dinâmica [...].
A opção de vinculação dinâmica de tipos foi incluída no C# 
2010. Uma variável pode ser declarada para usar vinculação 
de tipos dinâmica, com inclusão da palavra reservada dynamic 
em sua declaração, como no exemplo a seguir:
dynamic any;
[...] Em linguagens orientadas a objetos puras – por exemplo, 
Ruby –, todas as variáveis são referenciadas e não possuem 
tipos; todos os dados são objetos e qualquer variável pode 
referenciar qualquer objeto. De certo modo, nessas linguagens 
as variáveis são todas do mesmo tipo – elas são referências 
[...].
SEBESTA, 2018, p. 205-206.
 
Vinculações de armazenamento:
✓ Alocação: reserva da célula de memória à qual uma variável será 
vinculada a partir das células disponíveis.
✓ Liberação ou desalocação: devolução da célula de memória ao 
conjunto de células disponíveis, quando a variável não mais 
necessitar dela.
 
Tempo de vida: prazo em que a variável permanece vinculada à uma célula de memória. As 
classificações, por tempo de vida, são:
✓ Variáveis estáticas: “vinculadas a células de memória antes da execução, permanecendo 
na mesma célula de memória durante toda a execução. Exemplos: variáveis em FORTRAN 
77, variáveis estáticas em C (cláusula static)” (OLIVETE JÚNIOR, 2019, slide 45).
✓ Variáveis dinâmicas da pilha (stack): “vinculações são criadas quando suas sentenças de 
declaração são efetuadas, mas o tipo é estaticamente vinculado. Ex: em Java, as 
declarações de variáveis que aparecem no início de um método são elaboradas quando o 
método é chamado e as variáveis definidas por essas declarações são liberadas quando o 
método completa sua execução” (OLIVETE JÚNIOR, 2019, slide 47).
✓ Variáveis dinâmicas do monte (heap) explícitas: “[...] são células de memória não 
nomeadas (abstratas), que são alocadas e liberadas por instruções explícitas, especificadas 
pelo programador, que tem efeito durante a execução. Essas variáveis, alocadas a partir do 
monte e liberadas para o monte podem ser referenciadas por ponteiros. Exemplos: objetos 
dinâmicos em C e tudo em JAVA” (OLIVETE JÚNIOR,2019, slide 49-50).
✓ Variáveis dinâmicas do monte (heap) implícitas: “[...] são vinculadas ao armazenamento 
no monte (heap) apenas quando são atribuídos valores a elas. Exemplo [em] PHP: 
$alunos = (2, 5, 6, 1); // independente do que a variável $alunos foi usada, 
agora ela passa ser um vetor de inteiros com 4 valores numéricos” (OLIVETE 
JÚNIOR, 2019, slide 52).
 
ESCOPO
 
[...] O escopo de uma variável é a faixa de sentenças nas quais ela é 
visível. Uma variável é visível em uma sentença se ela pode ser 
referenciada ou atribuída nessa sentença.
As regras de escopo de uma linguagem definem como determinada 
ocorrência de um nome é associada a uma variável ou, no caso de uma 
linguagem funcional, como um nome é associado a uma expressão. Em 
particular, as regras de escopo determinam como referências a 
variáveis declaradas fora do subprograma ou bloco em execução são 
associadas às suas declarações e, logo, aos seus atributos [...]. 
Portanto, um claro entendimento dessas regras para uma linguagem é 
essencial para a habilidade de escrever ou ler programas nela.
Uma variável é LOCAL a uma unidade ou a um bloco de programa se 
for declarada lá. As variáveis NÃO LOCAIS de uma unidade ou de um 
bloco de programa são aquelas visíveis dentro da unidade ou do 
bloco de programa, mas não declaradas nessa unidade ou nesse bloco. 
Variáveis GLOBAIS são uma categoria especial de variáveis não 
locais [...].
SEBESTA, 2018, p. 211.
 
ALGOL 60 introduziu o método de vincular nomes a variáveis não 
locais, chamado de escopo estático [(ou escopo léxico)], copiado por 
muitas linguagens imperativas subsequentes e também por muitas 
linguagens não imperativas. O escopo estático é assim chamado 
porque o escopo de uma variável pode ser determinado estaticamente 
 ou seja, – ou seja, ANTES DA EXECUÇÃO. Isso permite a um leitor de programas 
humano (e a um compilador) determinar o tipo de cada variável no 
programa simplesmente examinando seu código fonte.
Existem duas categorias de linguagens de escopo estático: aquelas 
nas quais os subprogramas PODEM SER ANINHADOS, as quais criam 
escopos estáticos aninhados, e aquelas nas quais os subprogramas NÃO 
PODEM SER ANINHADOS. Na última categoria, os escopos estáticos 
também são criados para subprogramas, mas os aninhados são criados 
apenas por definições de classes aninhadas ou de blocos aninhados.
Ada, JavaScript, Common Lisp, Scheme, Fortran 2003+, F# e Python 
permitem subprogramas aninhados, mas as linguagens baseadas em C 
[(C, Objective-C, C++, Java e C#)] não.
SEBESTA, 2018, p. 211.
 
Considere a função [de] JavaScript a seguir, big, na qual as duas funções 
sub1 e sub2 são aninhadas:
function big() {
function sub1() {
var x = 7;
sub2();
}
function sub2() {
var y = x;
}
var x = 3;
sub1();
}
De acordo com o escopo estático, a referência à variável x em sub2 é para x 
declarado no procedimento big. Isso é verdade porque a busca por x começa 
no procedimento no qual a referência ocorre, sub2, mas nenhuma declaração 
para x é encontrada lá. A busca continua no pai estático de sub2, big, onde a 
declaração de x é encontrada. O x declarado em sub1 é ignorado porque não 
está nos acestrais estáticos de sub2.
SEBESTA, 2018, p. 212.
 
Em linguagens que usam escopo estático, independentemente 
de ser permitido o uso de subprogramas aninhados ou não, 
algumas declarações de variáveis podem ser ocultadas de 
outros segmentos de código. Por exemplo, considere mais uma 
vez a função [de] JavaScript big. A variável x é declarada 
tanto em big quanto em sub1, aninhado dentro de big. Dentro 
de sub1, toda referência simples a x é para o x local. 
Portanto, o x mais externo é ocultado de sub1.
SEBESTA, 2018, p. 213.
 
Blocos. Muitas linguagens permitem que novos escopos estáticos sejam 
definidos no meio do código executável. Esse poderoso conceito, introduzido 
em ALGOL 60, permite a uma seção de código ter suas próprias variáveis 
locais, cujo escopo é minimizado. Tais variáveis são dinâmicas da pilha, de 
forma que seu armazenamento é alocado quando a seção é alcançada e 
liberado quando a seção é abandonada. Essa seção de código é denominada 
bloco. Os blocos dão origem à frase linguagem estruturada por blocos.
As linguagens baseadas em C [(C, Objective-C, C++, Java e C#)] permitem que 
quaisquer sentenças compostas (uma sequência de sentenças envoltas em 
chaves correspondentes - {}) tenham declarações e, dessa forma, definam um 
novo escopo. Tais sentenças compostas são denominadas blocos. Por exemplo, se 
list fosse um vetor de inteiros, alguém poderia escrever o seguinte:
if(list[i] < list[j]) {
int temp;
temp = list[i];
list[i] = list[j];
list[j] = temp;
}
SEBESTA, 2018, p. 213.
 
Os escopos criados por blocos, que podem ser aninhados em blocos maiores, são 
tratados exatamente como aqueles criados por subprogramas. Referências a 
variáveis em um bloco e que não estão declaradas lá são conectadas às 
declarações por meio da busca pelos escopos que o envolvem (blocos ou 
subprogramas), por ordem de tamanho (do menor para o maior).
Considere o esqueleto da função em C:
void sub() {
int count;
...
while(...) {
int count;
count++;
...
}
...
}
A referência a count no laço de repetição while é para count local do laço. 
Nesse caso, o count de sub é ocultado do código que está dentro do laço while [...].
SEBESTA, 2018, p. 213.
 
Ordem de Declaração. Em C89, bem como em outras linguagens, 
todas as declarações de dados em uma função, exceto aquelas 
em blocos aninhados, devem aparecer no início da função. 
Contudo, algumas linguagens por exemplo, C99, C++, Java, – ou seja, 
JavaScript, and C# – permitem que declarações de variáveis 
apareçam em qualquer lugar possível de uma instrução 
aparecer em uma unidade do programa. Declarações podem 
criar escopos que não estejam associados com instruções 
compostas ou subprogramas. Por exemplo, em C99, C++ e Java, 
o escopo de todas as variáveis locais vai do ponto de suas 
declarações até o fim do bloco no qual essas declarações 
aparecem.
SEBESTA, 2016, p. 239.
 
Em C#, o escopo de qualquer variável declarada em um bloco 
pertence ao bloco inteiro, independente da posição da 
declaração no bloco, desde que não esteja em um bloco 
aninhado. O mesmo acontece para métodos [...].
[...] Em JavaScript, variáveis locais podem ser declaradas em 
qualquer lugar de uma função, mas o escopo de tal variável 
pertence sempre à função inteira. Se usada antes de sua 
declaração na função, tal variável tem o valor undefined. A 
referência não é ilegal.
As instruções for de C++, Java e C# permitem definições de 
variáveis em suas expressões de inicialização. Nas primeiras 
versões de C++, o escopo de tal variável ia de sua definição 
até o fim do menor bloco delimitador. Na versão padrão, 
contudo, o escopo está restrito ao construtor do for, como é 
o caso de Java e C#. [...]
SEBESTA, 2016, p. 240.
 
Escopo Global. Algumas linguagens, incluindo C, C++, PHP, JavaScript e 
Python, permitem que a estrutura de um programa seja uma sequência de 
definições de função, na qual as definições de variáveis podem aparecer 
fora das funções. Definições fora de funções de um arquivo criam 
variáveis globais, que podem estar potencialmente visíveis àquelas 
funções.
C e C++ têm declarações e definições de dados globais. Declarações 
especificam tipos e outros atributos, mas não causam alocação de 
armazenagem [na memória]. Definições especificam atributos e causam 
alocação de armazenagem [na memória]. Para um nome global específico, 
um programa em C pode ter qualquer quantidade de declarações 
compatíveis, mas somente uma única definição.
Uma declaração de uma variável fora das definições da função 
especifica que a variável está definida em um arquivo diferente. Uma 
variável global em C está implicitamente visível a todas as funções 
subsequentes do arquivo, exceto aquelas que incluem a declaração de 
uma variável local com o mesmo nome. [...]
SEBESTA, 2016, p.241.
 
Em C++, uma variável global que esteja oculta por uma local de mesmo nome pode 
ser acessada usando-se o operador de escopo (::). Por exemplo, se x é uma 
variável global oculta em uma função por uma local chamada x, a global 
poderia ser referenciada como ::x.
Instruções PHP podem ser intercaladas com definições de função. Variáveis em 
PHP são implicitamente declaradas quando aparecem em instruções. Qualquer 
variável que esteja implicitamente declarada fora de qualquer função é uma 
variável global; variáveis implicitamente declaradas dentro de funções são 
variáveis locais. O escopo de variáveis globais se estende de suas declarações 
até o fim do programa, mas ignora quaisquer definições de função subsequentes 
[...].
[...] As variáveis globais de JavaScript são muito similares às de PHP, exceto que 
não há modo de se acessar uma variável global em uma função que tenha 
declarado uma variável local com o mesmo nome.
As regras de visibilidade de variáveis globais em Python são incomuns. 
Variáveis não são normalmente declaradas, como em PHP. Elas são implicitamente 
declaradas quando aparecem como objetos de instruções de atribuição. Uma 
variável global pode ser referenciada em uma função, mas só pode ser atribuída 
em uma função se tiver sido declarada como global da função. [...]
SEBESTA, 2016, p. 241-242.
 
Avaliação de Escopo Estático. O escopo estático provê um método de acesso não 
local que funciona bem em muitas situações. Contudo, ele não está livre de 
problemas. Primeiro, na maioria dos casos, ele permite mais acesso a variáveis e 
subprogramas que o necessário. É simplesmente uma ferramenta muito grosseira 
para especificar de modo conciso tais restrições. Segundo, e talvez mais 
importante, é um problema relacionado à evolução do programa. O software é 
altamente dinâmico - programas utilizados regularmente mudam continuamente. 
Essas mudanças muitas vezes resultam em restruturação, destruindo, assim, a 
estrutura inicial que restringia o acesso de variáveis e subprogramas em uma 
linguagem como escopo estático. Para evitar a complexidade de se manter essas 
restrições de acesso, os desenvolvedores muitas vezes descartam a estrutura 
quando ela fica no caminho. Deste modo, contornar as restrições de escopo 
estático pode levar a projetos de programas que têm pouca semelhança com o 
original, até em áreas do programa nas quais as mudanças não foram feitas. 
Projetistas são encorajados a usar muito mais [variáveis globais] que o 
necessário. Todos os subprogramas pode terminar sendo aninhados no mesmo 
nível, no programa principal, usando-se [variáveis] globais em vez de níveis mais 
profundos de aninhamento. [...] Além disso, o projeto final pode ser desajeitado e 
artificial, e pode não refletir o projeto conceitual em questão [...]. Uma 
alternativa ao uso de escopo estático para controlar acesso a variáveis e 
subprogramas é um construtor de encapsulamento, o qual está incluído em 
muitas linguagens mais recentes [...].
SEBESTA, 2016, p. 244.
 
Escopo Dinâmico. O escopo de variáveis em APL, SNOBOL4 e 
nas primeiras versões de Lisp é dinâmico. Perl e Common 
Lisp também permitem que variáveis sejam declaradas de 
modo a ter escopo dinâmico, embora o mecanismo de escopo 
padrão nestas linguagens seja estático. O escopo dinâmico 
está baseado na sequência de chamadas de subprogramas, 
não em seu relacionamento espacial entre si. Deste modo, 
o escopo [dinâmico] pode ser determinado somente em 
TEMPO DE EXECUÇÃO.
SEBESTA, 2016, p. 244.
 
Considere de novo a função big [...], reproduzida aqui, menos as chamadas 
às funções:
function big() {
function sub1() {
var x = 7;
}
function sub2() {
var y = x;
var z = 3;
}
var x = 3;
}
Assuma que as regras de escopo dinâmico se aplicam a referências não 
locais. O significado do identificador x referenciado em sub2 é dinâmico 
 não pode ser determinado em tempo de compilação. Ele pode – ou seja, 
referenciar a variável a partir da declaração de x, dependendo da 
sequência de chamada.
SEBESTA, 2016, p. 244-245.
 
Avaliação de Escopo Dinâmico. O efeito do escopo dinâmico 
na programação é profundo. Quando o escopo dinâmico é 
usado, os atributos corretos das variáveis não locais 
visíveis à instrução de um programa não pode ser 
determinada estaticamente. Além do mais, uma referência ao 
nome de tal variável nem sempre é para a mesma variável. 
Uma instrução em um subprograma que contenha uma 
referência a uma variável não local pode se referir a 
variáveis não locais diferentes durante execuções 
diferentes do subprograma. Vários tipos de problemas de 
programação resultam diretamente do escopo dinâmico.
SEBESTA, 2016, p. 245.
 
Primeiro, durante o intervalo de tempo que começa quando um subprograma 
inicia sua execução e termina quando essa execução termina, as variáveis locais 
do subprograma estão todas visíveis para qualquer outro subprograma em 
execução, independente de sua proximidade textual ou de como a execução 
chegou ao subprograma atualmente em execução. Não há como proteger variáveis 
locais dessa acessibilidade. Os subprogramas são sempre executados no ambiente 
de todos os subprogramas previamente chamados que ainda não concluíram suas 
execuções. Como resultado, o escopo dinâmico resulta em programas menos 
confiáveis do que o escopo estático.
Um segundo problema com o escopo dinâmico é a incapacidade de digitar 
referências de verificação a [variáveis] estaticamente não locais. Esse problema 
resulta da incapacidade de encontrar estaticamente a declaração de uma 
variável referenciada como não local.
O escopo dinâmico também torna os programas mais difíceis de se ler, porque a 
sequência de chamadas dos subprogramas deve ser conhecida para determinar o 
significado das referências às variáveis não locais. Essa tarefa pode ser 
virtualmente impossível para um leitor humano.
Finalmente, acessos a variáveis não locais em linguagens de escopo dinâmico 
gastam mais tempo que acessos a [variáveis] não locais quando o escopo estático é 
usado [...].
SEBESTA, 2016, p. 245-246.
 
Por outro lado, o escopo dinâmico não é destituído de 
mérito. Em muitos casos, os parâmetros passados de um 
subprograma para outro são variáveis que estão definidas 
no chamador. Nenhuma delas precisa ser passada em uma 
linguagem de escopo dinâmico, porque estão implicitamente 
visíveis no subprograma chamado.
Não é difícil entender por que o escopo dinâmico não é 
amplamente usado quanto o escopo estático. Programas em 
linguagens de escopo estático são mais fáceis de se ler, mais 
confiáveis, e executam mais rápido que programas 
equivalentes em linguagens de escopo dinâmico. Foi 
precisamente por essas razões que o escopo dinâmico foi 
substituído pelo escopo estático na maioria dos dialetos 
recentes de Lisp [...].
SEBESTA, 2016, p. 246.
 
Escopo e Tempo de Vida. Às vezes, o escopo e o tempo de vida de uma 
variável parecem estar relacionados. Por exemplo, considere uma 
variável que esteja declarada em um método Java que não contenha 
chamadas a métodos. O escopo de tal variável vai da sua declaração até 
o fim do método. O tempo de vida daquela variável é o período de tempo 
que começa quando se entra no método e termina quando a execução do 
método termina. Embora o escopo e o tempo de vida da variável 
claramente não sejam o mesmo, porque o escopo estático é um conceito 
textual ou espacial, enquanto o tempo de vida é um conceito temporal, 
eles pelo menos parecem estar relacionados neste caso.
Essa aparente relação entre escopo e tempo de vida não se sustenta em 
outras situações. Em C e C++, por exemplo, uma variável que está 
declarada em uma função usando o especificador static é estaticamente 
vinculada ao escopo dessa função e também é estaticamente vinculada 
ao armazenamento [na memória]. Então, seu escopo é estático e local para 
a função, mas seu tempo de vida se estende por toda a execução do 
programa do qual faz parte.
SEBESTA, 2016, p. 246.
 
Ambientes de Referenciamento.O ambiente de referenciamento de uma 
instrução é a coleção de todas as variáveis que estão visíveis na 
instrução. O ambiente de referenciamento de uma instrução em uma 
linguagem de escopo estático é as variáveis declaradas em seu escopo 
local mais a coleção de todas as variáveis de seus escopos ancestrais 
que estão visíveis. Em tal linguagem, o ambiente de referenciamento de 
uma instrução é necessário enquanto essa instrução está sendo 
compilada, então, estruturas de código e dados podem ser criadas para 
permitir referências a variáveis de outros escopos durante o tempo de 
execução [...].
Em Python, os escopos podem ser criados por definições de função. O 
ambiente de referenciamento de uma instrução inclui as variáveis 
locais, além de todas as variáveis declaradas nas funções nas quais a 
instrução está aninhada (excluindo variáveis em escopos não locais 
ocultos por declarações em funções mais próximas). Cada definição de 
função cria um novo escopo e, deste modo, um novo ambiente.
SEBESTA, 2016, p. 247.
 
Considere o seguinte programa esquelético de Python:
g = 3; # A global
def sub1():
a = 5; # Creates a local
b = 7; # Creates another local
. . . <------------------------------ 1
def sub2():
global g; # Global g is now assignable here
c = 9; # Creates a new local
. . . <------------------------------ 2
def sub3():
nonlocal c: # Makes nonlocal c visible here
g = 11; # Creates a new local
. . . <-------------------------- 3
Os ambientes de referenciamento dos pontos do programa indicado são os 
seguintes:
Point Referencing Environment
1 local a and b (of sub1), global g for reference, but not for assignment
2 local c (of sub2), global g for both reference and for assignment
3 nonlocal c (of sub2), local g (of sub3)
SEBESTA, 2016, p. 247.
 
Constantes Nomeadas. Uma constante nomeada é uma variável 
que é vinculada a um valor apenas uma vez. Constantes 
nomeadas são úteis como auxílio para a legibilidade e a 
confiabilidade do programa. A legibilidade pode ser 
melhorada, por exemplo, usando o nome pi em vez da 
constante 3.14159265. Outro uso importante de constantes 
nomeadas é para parametrizar um programa. Por exemplo, 
considere um programa que processa uma quantidade fixa de 
valores de dados, digamos 100. Tal programa geralmente usa 
a constante 100 em uma quantidade de locais [diferentes], 
para declarar intervalos subscritos de arranjos e limites 
de controle de loops. [...]
SEBESTA, 2016, p. 248-249.
 
TIPOS DE DADOS 
PRIMITIVOS
 
Os tipos de dados que NÃO são definidos em termos de outros tipos são 
chamados de tipos de dados primitivos. Praticamente todas as 
linguagens de programação fornecem um conjunto de tipos de dados 
primitivos. Alguns dos tipos primitivos são meramente reflexos do 
hardware - por exemplo, a maioria dos tipos inteiros. Outros requerem 
apenas um pouco de suporte não-hardware para a sua implementação.
Para se especificar tipos estruturados, os tipos de dados primitivos de 
uma linguagem são usados junto com um ou mais construtores de tipo.
SEBESTA, 2016, p. 262.
 
Tipos numéricos
Algumas das primeiras linguagens de programação só tinham 
tipos primitivos numéricos. Os tipos numéricos ainda 
desempenham um papel central entre as coleções de tipos 
suportados por linguagens contemporâneas.
SEBESTA, 2016, p. 262.
A seguir, são apresentados alguns tipos numéricos.
 
Inteiro [(integer)]. O tipo de dados numérico primitivo mais comum é inteiro. O 
hardware de muitos computadores suporta vários tamanhos de inteiros. Esses 
tamanhos [...], e geralmente alguns outros, são suportados por algumas linguagens de 
programação. Por exemplo, o Java inclui quatro tamanhos inteiros SINALIZADOS 
[(signed - positivos e negativos)]: byte, short, int e long. Algumas linguagens, por 
exemplo, C++ e C#, incluem tipos inteiros NÃO SINALIZADO [(unsigned - apenas 
positivos)] [...]. Um valor inteiro sinalizado é representado em um computador por uma 
sequência de bits, com um dos bits (normalmente o mais à esquerda) representando o 
sinal. A maioria dos tipos inteiros é suportada diretamente pelo hardware. Um 
exemplo de um tipo inteiro que não é suportado diretamente pelo hardware é o tipo 
inteiro LONGO [(long)] do Python (F# também fornece tais inteiros). Valores desse 
tipo podem ter comprimento ilimitado. Valores inteiros longos podem ser 
especificados como literais, como no exemplo a seguir: 243725839182756281923L[.] 
Operações aritméticas inteiras no Python que produzem valores grandes demais 
para serem representados com o tipo int os armazenam como valores de tipo inteiro 
longo.
Um inteiro negativo pode ser armazenado em notação de magnitude de sinal, no qual 
o bit de sinal é definido para indicar o sinal negativo e o restante da sequência 
de bits representa o valor absoluto do número. A notação de magnitude de sinal, 
contudo, não se presta à aritmética computacional. A maioria dos computadores 
agora usa uma notação chamada COMPLEMENTO DE DOIS [(twos complement)] para 
armazenar inteiros negativos, o que é conveniente para a adição e a subtração [...].
SEBESTA, 2016, p. 262-263.
 
Ponto flutuante [(floating-point)]. Os tipos de dados de ponto flutuante modelam os 
números reais, mas as representações são APENAS APROXIMAÇÕES para muitos dos 
valores propriamente ditos [...]. Na maioria dos computadores, números do tipo ponto 
flutuante são armazenados em binário, o que agrava o problema. Por exemplo, mesmo 
o valor 0,1 em decimal não pode ser representado por um número finito de dígitos 
binários. Outro problema com os tipos de ponto flutuante é a perda de precisão em 
operações aritméticas [...].
Os valores de ponto flutuante são representados como frações e expoentes [...]. [...] [A 
maioria dos computadores mais novos] usa o formato padrão IEEE Floating-Point 754 
[para representá-los]. Os implementadores de linguagem usam qualquer 
representação suportada pelo hardware. A maioria das linguagens inclui dois tipos 
de ponto flutuante, geralmente chamados de float e double. O tipo float é o 
tamanho padrão, geralmente armazenado em quatro bytes de memória. O tipo double 
é fornecido para situações em que partes fracionárias maiores e/ou intervalos de 
expoentes maiores são necessários. Variáveis de precisão dupla geralmente ocupam o 
dobro do espaço de armazenamento das variáveis float e fornecem pelo menos o 
dobro do número de bits da fração.
A coleção de valores [...] representados por um tipo de ponto flutuante é definida 
em termos de precisão e intervalo. PRECISÃO é a precisão da parte fracionária de 
um valor, medida em termos de número de bits. INTERVALO é uma combinação do 
intervalo de frações e, mais importante, do intervalo de expoentes [...].
SEBESTA, 2016, p. 263.
 
Complexos. Algumas linguagens de programação suportam um tipo de dados 
complexos - por exemplo, Fortran e Python. Valores complexos são 
representados como pares ordenados de valores de ponto flutuante [...]. As 
linguagens que suportam um tipo complexo incluem operações para a 
aritmética de valores complexos.
Decimal [(decimal)]. A maioria dos computadores maiores projetados para 
oferecer suporte a aplicativos de sistemas de negócios possui suporte de 
hardware para tipos de dados decimais. Tipos de dados decimais 
armazenam um número fixo de dígitos decimais, com o ponto decimal 
implícito em uma posição fixa no valor. Esses são os principais tipos de 
dados para o processamento de dados de negócios e, portanto, são 
essenciais para COBOL. C# e F# também possuem tipos de dados decimais.
Tipos decimais têm a vantagem de ser capaz de armazenar precisamente 
valores decimais, pelo menos aqueles dentro de um intervalo restrito, o 
que não pode ser feito com ponto flutuante. Por exemplo, o número 0,1 (em 
decimal) pode ser exatamente representado em um tipo decimal, mas não em 
um tipo de ponto flutuante [...]. As desvantagens dos tipos decimais são 
que o intervalo de valores é restrito, porque nenhum expoente é 
permitido,e sua representação na memória é ligeiramente perdulária [...].
SEBESTA, 2016, p. 264.
 
Tipos booleanos
Os tipos booleanos são talvez os mais simples de todos os tipos. Seu 
intervalo de valores tem apenas dois elementos: um para verdadeiro e 
um para falso. Eles foram introduzidos no ALGOL 60 e incluídos na 
maioria das linguagens de propósito geral projetadas desde 1960. Uma 
exceção popular é C89, em que expressões numéricas são usadas como 
condicionais. Em tais expressões, todos os operandos com valores 
diferentes de zero são considerados verdadeiros e zero é considerado 
falso. Embora C99 e C++ tenham um tipo booleano, eles também permitem 
que expressões numéricas sejam usadas como se fossem booleanas. Este 
não é o caso das linguagens subsequentes, Java e C#.
Tipos booleanos são frequentemente usados para representar switches 
ou flags em programas. Embora outros tipos, como inteiros, possam ser 
usados para esses propósitos, o uso de tipos booleanos é mais legível.
Um valor booleano pode ser representado por um único bit, mas pelo 
fato de um único bit de memória não pode ser acessado de modo eficiente 
em muitas máquinas, elas são frequentemente armazenadas na menor 
célula de memória eficientemente endereçável, normalmente um byte.
SEBESTA, 2016, p. 265.
 
Tipos caracteres
Os dados de caracteres são armazenados em computadores como códigos numéricos. 
Tradicionalmente, a codificação mais usada era o código de 8 bits ASCII (American 
Standard Code for Information Interchange), empregando os valores 0 a 127 para 
codificar 128 caracteres diferentes. O ISO 8859-1 é outro código de caracteres de 8 
bits, mas permite 256 caracteres diferentes.
Devido à globalização dos negócios e à necessidade de os computadores comunicarem-
se entre si em todo o mundo, o conjunto de caracteres ASCII tornou-se inadequado. 
Em resposta, em 1991, o Unicode Consortium publicou o padrão UCS-2, um conjunto de 
caracteres de 16 bits, frequentemente chamado de Unicode. O Unicode inclui os 
caracteres da maioria dos idiomas naturais do mundo, por exemplo, o alfabeto 
cirílico, usado na Sérvia, e os dígitos tailandeses. Os primeiros 128 caracteres do 
Unicode são idênticos aos do ASCII. O Java foi a primeira linguagem popular a usar 
o [...] Unicode, desde então, seguida por JavaScript, Python, Perl, C# e F#.
Depois de 1991, o Unicode Consortium, em cooperação com a International Standards 
Organization (ISO), desenvolveu um código de 4 bytes chamado UCS-4, ou UTF-32, 
descrito na norma ISO/IEC 10646, publicada em 2000. Para fornecer os meios de 
processar codificações de caracteres únicos, a maioria das linguagens de 
programação inclui um tipo primitivo para elas. No entanto, o Python suporta 
caracteres únicos apenas como sequências de caracteres de comprimento 1.
SEBESTA, 2016, p. 265-266.
 
TIPOS DE DADOS DE 
CADEIAS DE CARACTERES 
(STRINGS)
 
Um tipo de cadeia de caracteres [(string)] é aquele em que 
os valores consistem em sequências de caracteres. As 
constantes de cadeia de caracteres são usadas para 
rotular a saída e a entrada e saída de todos os tipos de 
dados se dão frequentemente em termos de seqüências de 
caracteres. Naturalmente, as cadeias de caracteres 
também são um tipo essencial para todos os programas 
que fazem manipulação de caracteres.
SEBESTA, 2016, p. 266.
 
Questões de projeto. As duas questões de projeto mais 
importantes, específicas para tipos de cadeia de caracteres, 
são as seguintes:
 • As sequências devem ser um tipo especial de arranjo de 
caracteres ou um tipo primitivo?
 • As strings devem ter comprimento estático ou dinâmico?
SEBESTA, 2016, p. 266.
 
Cadeias de caracteres e suas operações. As operações de strings mais 
comuns são ATRIBUIÇÃO, CONCATENAÇÃO, REFERÊNCIA DE SUBSTRING, 
COMPARAÇÃO E CORRESPONDÊNCIA DE PADRÕES.
Uma referência de substring é uma referência a uma substring de 
determinada string. As referências de substring são discutidas no 
contexto mais geral de arranjos, em que são chamadas de fatias [(slices)].
Em geral, as operações de atribuição e comparação em cadeias de 
caracteres são complicadas pela possibilidade de haver operandos de 
strings de diferentes comprimentos. Por exemplo, o que acontece quando 
uma string mais longa é atribuída a uma string mais curta ou vice-
versa? Geralmente, escolhas simples e sensatas são feitas nessas 
situações, embora os programadores frequentemente tenham dificuldade 
de lembrar delas.
Em algumas linguagens, a correspondência de padrões é suportada 
diretamente. Em outras, é fornecida por meio de uma função ou 
biblioteca de classes.
SEBESTA, 2016, p. 266.
 
Se as strings não forem definidas como um tipo primitivo, os dados da 
string serão geralmente armazenados em arranjos de caracteres únicos e 
referenciados como tal na linguagem. Essa é a abordagem adotada em C e 
C++, que usam arranjos do tipo char para armazenar cadeias de 
caracteres. Essas linguagens fornecem uma coleção de operações de 
strings por meio de bibliotecas padrão. Muitos usuários de strings e 
muitas das funções de biblioteca usam a convenção de que as cadeias de 
caracteres são terminadas com um caractere especial, null [(\0)], 
representado por zero. Esta é uma alternativa para manter o 
comprimento das variáveis do tipo string. As operações de biblioteca 
simplesmente executam suas operações até que o caractere nulo apareça 
na string que está sendo operada. Funções de biblioteca que produzem 
strings frequentemente fornecem o caractere nulo.
SEBESTA, 2016, p. 266.
 
Opções de comprimento de cadeias de caracteres (strings). Existem várias 
escolhas de projeto relacionadas ao comprimento dos valores de strings. 
Primeiro, o comprimento pode ser estático e definido quando a string é 
criada. Tal string é chamada de STRING DE COMPRIMENTO ESTÁTICO. Essa 
é a escolha para as strings do Python, os objetos imutáveis da classe 
String do Java, bem como das classes similares da biblioteca de classes 
padrão do C++, a classe String interna do Ruby e a biblioteca de 
classes .NET disponível para C# e F#.
A segunda opção é permitir que as strings tenham comprimento variável 
até o máximo declarado e fixo, determinado na definição da variável, 
como exemplificado pelas strings em C e pelas strings do tipo C em C++. 
Essas são chamadas de STRINGS DE COMPRIMENTO DINÂMICO LIMITADO. 
Tais variáveis do tipo string podem armazenar qualquer quantidade de 
caracteres entre zero e o máximo [...].
A terceira opção é permitir que as strings tenham comprimento variável 
sem máximo, como em JavaScript, Perl e na biblioteca de C++ padrão. 
Essas são chamadas de STRINGS DE COMPRIMENTO DINÂMICO. Essa opção 
requer o custo de alocação e desalocação dinâmica de armazenagem [de 
memória], mas oferece flexibilidade máxima.
SEBESTA, 2016, p. 268-269.
 
Avaliação. Tipos de strings são importantes para a capacidade de 
escrita de uma linguagem. Lidar com strings como arranjos pode ser mais 
complicado do que com um tipo de string primitivo. Por exemplo, 
considere uma linguagem que trata strings como arranjos de caracteres 
e não possui uma função predefinida que faça o mesmo que strcpy do C. 
Então, a simples atribuição de uma string a outra exigiria um loop. A 
adição de strings como um tipo primitivo para uma linguagem não é 
dispendiosa em termos de complexidade de linguagem ou compilador. 
Portanto, é difícil justificar a omissão de tipos primitivos de strings 
em algumas linguagens contemporâneas. Naturalmente, fornecer strings 
por meio de uma biblioteca padrão é quase tão conveniente quanto tê-
las como um tipo primitivo.
As operações de strings, tais como a correspondência de padrão simples e 
concatenação, são essenciais e devem ser incluídas para valores do tipo 
string. Embora as strings de comprimento dinâmico sejam obviamente as 
mais flexíveis, o custo de sua implementação deve ser confrontado com 
essa flexibilidade adicional.
SEBESTA, 2016, p. 269.
 
Implementação de tipos de string de caracteres.Os tipos de strings de 
caracteres poderiam ser suportados diretamente no hardware; mas, na maioria 
dos casos, o software é usado para implementar o armazenamento, a recuperação 
e a manipulação de strings. Quando os tipos de strings de caracteres são 
representados como arranjos de caracteres, a linguagem frequentemente fornece 
poucas operações.
[...] As strings dinâmicas limitadas de C e C++ não exigem descritores de tempo de 
execução, porque o final de uma string é marcado com o caractere nulo. Eles não 
precisam do comprimento máximo, porque os valores de índice nas referências do 
arranjo não são verificados no intervalo dessas linguagens.
As strings de comprimento estático e de comprimento dinâmico limitado não 
requerem alocação de armazenamento dinâmico especial. No caso de strings de 
comprimento dinâmico limitado, o armazenamento suficiente para o comprimento 
máximo é alocado quando a variável do tipo string é vinculada ao 
armazenamento, então somente um único processo de alocação está envolvido.
As strings de comprimento dinâmico exigem gerenciamento de armazenamento 
mais complexo. O comprimento de uma string e, portanto, o armazenamento ao 
qual ela está vinculada, deve aumentar e diminuir dinamicamente.
SEBESTA, 2016, p. 269-270.
 
Há três abordagens para suportar alocação e desalocação dinâmicas de strings de 
comprimento dinâmico. Primeiro, elas podem ser armazenadas em uma lista 
encadeada, de modo que, quando crescer, as células recém-requeridas possam vir de 
qualquer lugar da pilha. As desvantagens são o armazenamento extra dos 
encadeamentos da lista e a complexidade necessária das operações de string.
A segunda é armazenar strings como arranjos de ponteiros para caracteres 
individuais, alocados na memória heap. Esse método ainda usa memória extra, mas o 
processamento pode ser mais rápido do que na abordagem de lista encadeada.
A terceira alternativa é armazenar strings completas em células de armazenamento 
adjacentes. O problema surge quando a string cresce: como o armazenamento 
adjacente às células existentes pode continuar a ser alocado [...]? Frequentemente, 
esse armazenamento não está disponível. Em vez disso, é encontrada uma nova área 
de memória que possa armazenar a nova string completa e a parte antiga é movida 
para essa área. Então, as células de memória usadas para a string antiga são 
desalocadas. Esta última abordagem é a normalmente usada [...].
Embora o método de lista encadeada exija mais armazenamento, os processos de 
alocação e desalocação associados são simples. Contudo, algumas operações de string 
são atrasadas por causa da busca do ponteiro requerido. Por outro lado, usar 
memória adjacente para strings completas resulta em operações mais rápidas e 
requer significativamente menos armazenamento, mas os processos de alocação e 
desalocação são mais lentos.
SEBESTA, 2016, p. 270-271.
 
TIPOS DE ENUMERAÇÃO
 
Um tipo de enumeração é aquele no qual todos os valores possíveis, que 
são constantes nomeadas, são fornecidos, ou enumerados, na definição. Os 
tipos de enumeração fornecem um modo de definir e agrupar coleções de 
constantes nomeadas, chamadas de constantes de enumeração. A definição 
de um tipo de enumeração típico é mostrada no seguinte exemplo C#:
enum days { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
As constantes de enumeração, em geral, são explicitamente atribuídas a 
valores inteiros: 0, 1..., mas pode ser explicitamente atribuída a 
qualquer literal inteira, na definição do tipo.
SEBESTA, 2016, p. 271.
 
Questões de projeto. As questões de projeto para tipos de enumeração são 
os seguintes:
 • É permitida que uma constante de enumeração apareça em mais de uma 
definição de tipo e, em caso afirmativo, como é o tipo de uma ocorrência 
dessa constante na verificação do programa?
 • Valores de enumeração são forçados para o tipo inteiro?
 • Existem outros tipos forçados para um tipo de enumeração?
Todos essas questões de projeto estão relacionadas à verificação de 
tipos. Se uma variável de enumeração for forçada para um tipo 
numérico, então haverá pouco controle sobre seu intervalo legal de 
operações ou seu intervalo de valores. Se um valor de tipo int for 
forçado para um tipo de enumeração, então uma variável de tipo de 
enumeração poderia ser atribuída a qualquer valor inteiro, 
independentemente de representar uma constante de enumeração ou não.
SEBESTA, 2016, p. 271.
 
Projetos. Em linguagens que não possuem tipos de enumeração, os 
programadores geralmente os simulam com valores inteiros. Por exemplo, 
suponha que precisássemos representar cores em um programa C e o C não 
tivesse um tipo de enumeração. Poderíamos usar 0 para representar 
azul, 1 para representar vermelho e assim por diante. Esses valores 
podem ser definidos da seguinte maneira:
int red = 0, blue = 1;
Agora, no programa, poderíamos usar vermelho e azul como se fosse de 
um tipo de cor. A problema com essa abordagem é que, pelo fato de não 
termos definido um tipo propriamente dito para nossas cores, não há 
verificação de tipo quando forem utilizadas [...].
C e Pascal foram as primeiras linguagem amplamente utilizadas a 
incluir tipos de dados de enumeração. O C++ inclui tipos de enumeração 
do C.
SEBESTA, 2016, p. 271-272.
 
Avaliação. Os tipos de enumeração podem fornecer vantagens quanto a 
legibilidade e confiabilidade. A legibilidade é aprimorada muito 
diretamente: os valores nomeados são reconhecidos facilmente, enquanto 
os valores codificados não.
Na área da confiabilidade, os tipos de enumeração de C#, F# e Java 5.0 
fornecem duas vantagens: (1) nenhuma das operações aritméticas é válida 
em tipos de enumeração; isso previne a adição de dias da semana, por 
exemplo, e (2) [...] a nenhuma variável de enumeração pode ser atribuído um 
valor de fora do seu intervalo definido. Se o tipo de enumeração cores 
tiver 10 constantes de enumeração e usar 0..9 como valores internos, 
nenhum número maior que 9 pode ser atribuído a uma variável deste tipo.
Pelo fato de o C tratar variáveis de enumeração como variáveis inteiras, 
ele não fornece nenhuma dessas duas vantagens. C++ é um pouco melhor. 
Valores numéricos podem ser atribuídos a variáveis do tipo enumeração 
somente se forem convertidos para o tipo da variável atribuída. Valores 
numéricos atribuídos a variáveis do tipo enumeração são verificados 
para determinar se estão no intervalo dos valores internos do tipo de 
enumeração. Infelizmente, se o usuário usar um intervalo amplo de 
valores explicitamente atribuídos, essa verificação não será efetiva [...].
SEBESTA, 2016, p. 273.
 
TIPOS DE ARRANJOS 
(VETORES E MATRIZES)
 
Um arranjo (array) é um agregado homogêneo de elementos de dados no qual 
um elemento individual é identificado por sua posição no agregado, em relação 
ao primeiro elemento. Os elementos de dados individuais de um arranjo são do 
mesmo tipo. Referências a elementos de arranjos individuais são especificadas 
usando expressões subscritas. Se quaisquer das expressões subscritas de uma 
referência incluir variáveis, então a referência exigirá um cálculo adicional 
em tempo de execução para determinar o endereço da localização de memória que 
está sendo referenciada.
Em muitas linguagens, como C, C ++, Java e C#, todos os elementos de um arranjo 
precisam ser do mesmo tipo. Nessas linguagens, os ponteiros e as referências são 
restritos para apontar ou referenciar um único tipo. Então, os objetos ou 
valores de dados que estão sendo apontados ou referenciados também são de um 
único tipo. Em algumas outras linguagens, como JavaScript, Python e Ruby, as 
variáveis são referências sem tipo a objetos ou valores de dados. Nesses casos, os 
arranjos ainda consistem em elementos de um único tipo, mas tais elementos 
podem referenciar objetos ou valores de dados de tipos diferentes. Esses 
arranjos ainda serão homogêneas, porque seus elementos serão do mesmo tipo.
C# e Java 5.0 fornecem arranjos genéricos, isto é, arranjos cujos elementossão 
referências a objetos, por meio de suas bibliotecas de classes.
SEBESTA, 2016, p. 274.
 
Questões de Projeto. As principais questões de projeto específicas para 
arranjos são as seguintes:
 • Quais tipos são válidos para os subscritos?
 • As expressões de subscrição no intervalo de referências de elementos 
são verificadas?
 • Quando os intervalos dos subscritos são vinculados?
 • Quando ocorre a alocação do arranjo?
 • São permitidos arranjos multidimensionais irregulares ou 
retangulares, ou ambos?
 • Os arranjos podem ser inicializados quando tiverem seu 
armazenamento alocado?
 • Quais tipos de fatias são permitidos, se houver?
SEBESTA, 2016, p. 274.
 
Arranjos e Índices. Os elementos específicos de um arranjos são 
referenciados por meio de um mecanismo sintático de dois níveis, em que 
a primeira parte é o nome agregado e a segunda parte é um seletor 
possivelmente dinâmico que consiste em um ou mais itens, conhecidos 
como subscritos ou índices. Se todos os índices de uma referência forem 
constantes, o seletor será estático; caso contrário, será dinâmico. A 
operação de seleção pode ser considerada como um mapeamento do nome 
do arranjo e do conjunto de valores de índices para um elemento da 
agregação. De fato, os arranjos são às vezes chamados de mapeamentos 
finitos. Simbolicamente, esse mapeamento pode ser mostrado como
nomeDoArranjo(listaDeValoresSubscritos) --> elemento
SEBESTA, 2016, p. 274-275.
 
A sintaxe das referências do arranjo é razoavelmente universal: o nome 
do arranjo é seguido pela lista de índices, envolvida por PARÊNTESES 
OU COLCHETES. Em algumas linguagens que fornecem arranjos 
multidimensionadas como arranjos de arranjos, cada índice aparece em 
seus próprios colchetes. Um problema com o uso de parênteses para 
incluir expressões subscritas é que elas frequentemente são usadas 
também para incluir os parâmetros de chamadas a subprogramas; esse 
uso faz com que as referências a arranjos se pareçam exatamente como 
essas chamadas. Por exemplo, considere a seguinte declaração de 
atribuição Ada:
Soma := Soma + B(I);
Pelo fato de os parênteses serem usados para parâmetros de 
subprogramas e para os índices de arranjos no Ada, os leitores do 
programa e os compiladores são forçados a usar outras informações para 
determinar se B(I) nessa atribuição é uma chamada de função ou uma 
referência a um elemento do arranjo. Isso resulta em legibilidade 
reduzida. [...] A maioria das linguagens que não o Fortran e o Ada usa 
colchetes para delimitar seus índices de arranjos.
SEBESTA, 2016, p. 275.
 
Vinculações dos Índices e Categorias de Arranjos. A vinculação do tipo de índice 
a uma variável do arranjo é geralmente estática, mas os intervalos de valores 
dos índices são às vezes vinculados dinamicamente. Em algumas linguagens, o 
limite inferior do intervalo dos índices é implícito. Por exemplo, nas 
linguagens baseadas em C, o limite inferior de todos os intervalos dos índices é 
fixado em 0. Em algumas outras linguagens, os limites inferiores dos intervalos 
dos índices devem ser especificados pelo programador [...].
Um arranjo estático (static array) é aquele no qual os intervalos dos índices são 
estaticamente vinculados e a alocação de armazenamento é estática (feita antes 
do tempo de execução). A vantagem dos arranjos estáticos é a eficiência: nenhuma 
alocação ou desalocação dinâmica é necessária. A desvantagem é que o 
armazenamento para o arranjo é fixo durante todo o tempo de execução do 
programa.
Um arranjo dinâmico de pilha fixa (fixed stack-dynamic array) é aquele em que 
os intervalos dos índices são estaticamente vinculados, mas a alocação é feita 
no momento da elaboração da declaração, durante a execução. A vantagem dos 
arranjos dinâmicos de pilha fixa sobre os arranjos estáticos é a eficiência do 
espaço. Um arranjo grande em um subprograma pode usar o mesmo espaço de um 
arranjo grande em um subprograma diferente, desde que ambos os subprogramas 
não estejam ativos ao mesmo tempo [...]. A desvantagem é o tempo necessário de 
alocação e desalocação.
SEBESTA, 2016, p. 276.
 
Um arranjo dinâmico de monte fixo (fixed heap-dynamic array) é semelhante a um 
arranjo dinâmico de pilha fixa (fixed stack-dynamic array), em que os 
intervalos dos índices e a vinculação de armazenamento são fixos após o 
armazenamento ser alocado. As diferenças são que os intervalos dos índices e do 
armazenamento são feitos quando o programa usuário os solicita durante a 
execução e o armazenamento é alocado no monte (heap), em vez de na pilha (stack). 
A vantagem dos arranjos dinâmicos de monte fixo é a flexibilidade: o tamanho 
do arranjo sempre se ajusta ao problema. A desvantagem é o tempo de alocação 
do monte (heap), que é maior que o tempo de alocação da pilha (stack).
Um arranjo dinâmico de monte (heap-dynamic array) é aquele em que a vinculação 
de intervalos dos índices e a alocação de armazenamento é dinâmica e pode ser 
alterada em qualquer quantidade de vezes durante a vida útil do arranjo. A 
vantagem dos arranjos dinâmicos de monte sobre os outros é a flexibilidade: os 
arranjos podem crescer e diminuir durante a execução do programa, a medida 
que a necessidade de espaço é alterada. A desvantagem é que a alocação e a 
desalocação demoram mais e podem acontecer muitas vezes durante a execução do 
programa [...].
SEBESTA, 2016, p. 276.
 
Inicialização de Arranjos. Algumas linguagens fornecem meios para 
inicializar arranjos no momento em que seu armazenamento é alocado. C, 
C ++, Java e C# permitem a inicialização de seus arranjos. Considere a 
seguinte declaração em C:
int list [] = { 4, 5, 7, 83 };
A lista do arranjo é criada e inicializada com os valores 4, 5, 7 e 83. O 
compilador também define o comprimento do arranjo. Esta deve ser uma 
conveniência, mas não sem custo. Ela efetivamente remove a 
possibilidade de o sistema detectar alguns tipos de erros do 
programador, como, por engano, deixar um valor fora da lista.
SEBESTA, 2016, p. 278.
 
[...] Cadeias de caracteres em C e C++ são implementadas como arranjos de char. 
Esses arranjos podem ser inicializados com constantes do tipo string, como em
char name [] = "freddie";
O arranjo name terá oito elementos, porque todas as strings são terminadas com 
um caractere nulo (zero), que é fornecido implicitamente pelo sistema para 
constantes do tipo string.
Arranjos de strings em C e C++ também podem ser inicializadas com literais do 
tipo string. Por exemplo, char *names [] = { "Bob", "Jake", "Darcie" };
Este exemplo ilustra a natureza das literais de caracteres em C e C++. No 
exemplo anterior, de uma string literal sendo usada para inicializar o arranjo 
do tipo char name, a literal é considerada como uma arranjo do tipo char. Mas, 
no último exemplo (names), as literais são consideradas como ponteiros para 
caracteres, então, o arranjo é um arranjo de ponteiros para caracteres. Por 
exemplo, names[0] é um ponteiro para a letra 'B' no arranjo de caracteres 
literais que contém os caracteres 'B', 'o', 'b' e o caractere nulo.
Em Java, uma sintaxe semelhante é usada para definir e inicializar uma matriz 
de referências a objetos String. Por exemplo,
String [] nomes = ["Bob", "Jake", "Darcie"];
SEBESTA, 2016, p. 278.
 
Operações de Arranjos. Uma operação de arranjos é aquela que opera em 
um arranjo como uma unidade e as mais comuns são ATRIBUIÇÃO, 
CONCATENAÇÃO, COMPARAÇÃO PARA IGUALDADE E DESIGUALDADE, e FATIAS 
[...].
As linguagens baseadas em C não fornecem nenhuma operação de arranjo, 
exceto por meio dos métodos de Java, C++ e C#. Perl suporta atribuições 
de arranjos, mas não oferece suporte a comparações. Os arranjos do 
Python são chamados de listas, embora tenham todas as características 
dos arranjos dinâmicos [...]. Tal como o Python, os elementos dos arranjos 
do Ruby são referências a objetos [...].
F# inclui muitos operadores de arranjos em seu módulo Array. Entre eles 
estão Array.append, Array.copy e Array.length.
SEBESTA, 2016,

Outros materiais