Escolar Documentos
Profissional Documentos
Cultura Documentos
No próximo passo vamos criar um projeto C que servirá de base para esta aula. Queremos utilizar
a extensão que instalámos, para tal precisamos de abrir a “Command Pallete” do VScode,
clicando na opção visível na imagem.
Em seguida abre um explorador de ficheiros na pasta “aula3”. Devem clicar no “open” sem
navegar para outra pasta, de forma a criar o projeto na pasta atual. Devem agora ter um conjunto
de pastas na vossa diretoria, com o seguinte aspecto. Utilizem as setas horizontais para expandir
as pastas e abrir o ficheiro “main.c”.
Editor de Texto
É a aplicação que irá permitir a escrita do programa. Inúmeros editores de texto estão disponíveis
em Linux, desde os mais simples (e.g., vim, nano) até aos mais complexos (e.g., emacs, visual
studio code) passando pelos mais clássicos (e.g., gedit), que fazem parte das aplicações
disponíveis na barra de comandos do ambiente gráfico.
Compilador C
Uma vez criado o programa em C, será necessário transformá-lo num programa executável. Para
que isto seja possível é utilizado o compilador C (gcc) que irá realizar uma série de operações
sobre o programa (englobando o pré-processamento, a verificação do código, a compilação, a
assemblagem e a edição de ligações), para finalmente consigamos obter a imagem executável.
Para realizar esta operação deverá ser executado o comando (por exemplo, na pasta do projeto
que criaram anteriormente):
$ gcc main.c
Se não for especificado o nome do ficheiro executável, este recebe o nome por defeito que é
a.out. Para definir o nome do programa executável utiliza-se a opção:
$ gcc main.c -o main
É também aconselhado utilizar a opção -Wall que, durante o processo de compilação, irá mostrar
warnings relativos a eventuais problemas que possam existir no código. De salientar que mesmo
que estes warnings sejam lançados, a não ser que exista algum erro, que o código irá ser
compilado na mesma. Estes avisos servem para dirigir o programador a determinadas partes do
código que eventualmente poderiam ser escritas de uma forma mais correta ou poderem
eventualmente gerar resultados que não são os esperados.
$ gcc main.c -o main -Wall
Execução e Depuração
A execução de um programa é realizada através da invocação do seu nome na linha de
comandos. Assim para executar o programa acima criado:
$ ./main
A utilização do “./” em frente do nome é necessária para que o bash procure o nome na pasta em
que foi criado o executável.
No caso do programa apresentar erros na sua execução que sejam difíceis de encontrar, pode-se
recorrer ao GNU Debugger, uma aplicação que permite realizar a execução do programa de forma
controlada.
Para tal é necessário compilar o programa com a opção -g de forma a que o executável guarde
informação adicional sobre o programa (tabela de símbolos, dentre outros):
$ gcc main.c -g -o main
Desta forma, o debugger toma o controlo da sessão, ou seja, os comandos inseridos serão agora
por ele interpretados, e não pela bash. Assim, a prompt que aparece agora é o seguinte:
(gdb)
As opções desta ferramenta são múltiplas pelo que convém consultar o manual de utilização,
através da invocação do comando man gdb (ou consultando o manual online).
Exemplo:
(gdb) l
1 main()
2 {
3 printf("Hello\n");
4 }
(gdb) b 3
Breakpoint 1 at 0x804837c: file hello.c, line 3.
(gdb) r
Starting program: /home/aluno/a123456/hello
Breakpoint 1, main () at hello.c:3
3 printf("Hello\n");
(gdb) s
Hello
4 }
Como se pode ver no exemplo a listagem, inserção de um breakpoint, execução do programa que
pára no breakpoint inserido, e a execução passo a passo da instrução printf. O programa
poderia ser assim executado passo a passo até se descobrir a eventual causa de erro.
As funções printf e scanf têm a sua implementação na biblioteca padrão de C (libc) e podem
ser utilizadas simplesmente através de incluir o ficheiro cabeçalho stdio.h. Já a utilização de
funções de outras bibliotecas, como por exemplo a libm, requerem a indicação ao GCC da
biblioteca a incluir através do parâmetro -l logo seguido da designação da biblioteca. Este
parâmetro pode surgir múltiplas vezes na linha de comando. Um exemplo de utilização de uma
função externa definida numa biblioteca que não é incluída automaticamente é a função que
calcula a potência de um valor:
O ficheiro fonte que utilizar esta função deve incluir no início o ficheiro math.h (que define apenas
a interface da função). O comando GCC para geração do executável deverá ser:
Makefiles
Um makefile é o ficheiro que automatiza a compilação de um projecto. Este permite não só a
compilação, mas também a limpeza dos ficheiros binários criados e a sua instalação no sistema
operativo. Permite ainda a criação de variáveis globais que serão tidas em conta na execução do
makefile. A compilação em C é realizada da seguinte forma
o que neste caso se traduziria, no mínimo, num Makefile com o seguinte aspeto:
main: main.c
gcc main.c –o main
no nosso caso, quando criámos o projeto no Visual Studio Code já foi criado um Makefile.
Portanto para utilizarmos o Makefile utilizamos o comando make, indicando o target que queremos
compilar, no mesmo caminho (path) onde estão os ficheiros C e o Makefile:
make main
Para visualizar as opções adicionais que estão disponíveis basta digitar man make.
Múltiplas opções
Podemos criar um Makefile com múltiplas opções, tais as que se ilustram de seguida:
De salientar que quando se executa o make sem fornecer nenhum parâmetro, que ele executará
por defeito a opção all, existindo também a opção clean que removerá os ficheiros binários
criados.
Variáveis e comentários
No make existe também a possibilidade de definirmos variáveis e comentários conforme o
exemplo que se segue:
#Um comentário
#CC, CFLAGS and EXECS são variáveis
CC = gcc
CFLAGS = -Wall
EXECS = file file2
all: $(EXECS)
file:
$(CC) $(CFLAGS) file.c –o file
file2:
$(CC) $(CFLAGS) file2.c –o file2
clean:
rm –f $(EXECS)
De notar que é também comum a utilização da variável LDFLAGS com opções para serem
passadas ao linking.
Compilação em múltiplas partes
Neste exemplo que se ilustra de seguida a compilação é realizada primeiro para objectos (*.o) e
só depois é criado o executável.
all: executable
main.o: main.c
gcc -c main.c -o main.o
Para compilar o nosso programa clicamos no botão de Build, assinalado na figura seguinte.
Será aberto um terminal onde é corrido o comando “make” para compilar o nosso projeto. O
output deve ter o seguinte aspecto.
Como o compilador “gcc” foi invocado com a flag “-Wall”, recebemos dois avisos devido a
parâmetros de entrada na nossa função “main” que não foram utilizados. No entanto, como não
são erros, o binário foi compilado corretamente.
O ficheiro “main.o” contém o código objeto do vosso “main.c”, antes de ser efetuado o “linking”, o
ficheiro “main.d” é um ficheiro auxiliar que lista as dependências necessárias para compilar o
“main.o”. Por último o ficheiro “main” é o binário, ou executável, do vosso projeto. Para correr o
nosso programa clicamos no botão “Run”, como na figura seguinte.
O VScode irá abrir outro terminal e executar o comando para lançar o binário “main” do nosso
projeto. Deverá ter o seguinte output.
O programa apenas escreve no “stdout” o string “Hello World!\n”, como pode ser confirmado no
terminal. Podemos utilizar o gdb dentro do IDE, utilizando a opção de debug da figura seguinte.
Os botões em cima permitem controlar a execução do código, “step over”, “step into”, “step out”,
“continue”, “restart” e “stop”. à esquerda temos a lista de variáveis dentro do scope atual.
Podemos confirmar que “argc=1”, porque o nosso programa foi chamado sem argumentos, e
“*argv” é um string que começa por “/hom”, com o resto omitido devido ao tamanho da janela. Em
baixo destacamos as seguintes janelas.
O menu da esquerda mostra o “Call Stack”, e permite também navegar para calls superiores ou
inferiores. O menu “breakpoints” mostra todos os breakpoints e permite desativar cada um,
individualmente. No centro temos um terminal de debug que permite executar comandos do gdb.
Por exemplo, se colocarmos “argv[0]”, o terminal vai imprimir o valor desta variável, que podemos
ver é “/home/ubuntu/aula3/output/main”, ou seja, é o caminho do nosso programa como foi
exemplificado pelo script da aula passada.
Exercícios Fundamentais
Num primeiro exercício vamos criar um programa que calcula a dimensão em volume de um
armário, recebendo 3 valores:
● Largura
● Comprimento
● Altura
#include <stdio.h>
#include <stdlib.h>
return EXIT_SUCCESS;
}
e poderão compilar e executar o mesmo no Visual Studio Code como vimos anteriormente.
Neste projeto devem criar um programa em C para calcular o número de lâmpadas 60 watts
necessárias para uma determinada divisão. O programa deverá ler um conjunto de informações,
tais como: tipo, largura e comprimento da divisão. O programa termina quando o tipo de divisão
for igual a -1 (menos um). A tabela abaixo mostra, para cada tipo de divisão, a quantidade de
watts por metro quadrado.
Tipo de divisão Potência
(watt/m2)
0 12
1 15
2 18
3 20
4 22
Dica: Use uma estrutura struct para agrupar logicamente as informações de uma divisão (int tipo
de divisao, float largura e float comprimento). Recorra a uma função (float CalculaArea) para
calcular a área da divisão. Os atributos de entrada serão a largura e comprimento da divisão.
Utilize uma função (float Lampada) para calcular a quantidade de lâmpadas necessárias para a
divisão. Os atributos de entrada serão o tipo de divisão e a área (em m2) da divisão.
Observações: Utilize a função ceil(numero) em #include <math.h> para realizar o arredondamento
para cima.
struct {
int tipo;
float larg, comp;
} divisao;
float nlampadas;
float tamanho;
printf("\n\nDigite o tipo de divisao (0 ate 4):");
scanf("%d", &divisao.tipo);
while(divisao.tipo != -1) {
printf("\n\nDigite a largura do divisao:");
scanf("%f", &divisao.larg);
printf("\n\nDigite o comprimento do divisao:");
scanf("%f", &divisao.comp);
tamanho = CalculaArea(divisao.larg, divisao.comp);
nlampadas = Lampada(divisao.tipo, tamanho);
printf("\n\n Para a area da sua divisao precisara de %f
lampadas",ceil(nlampadas));
printf("\n\nDigite o tipo de divisao (0 ate 4):");
scanf("%d", &divisao.tipo);
}
}