INF1018 - Software Básico

Aquecimento

Nesse laboratório, você vai aprender a compilar programas no ambiente linux/gcc.

  1. Abra um terminal onde você irá interagir com o sistema através de linha de comando.

  2. Na interação por linha de comando, existe o conceito de diretório corrente, que é a pasta de arquivos onde você está "posicionado''. Escreva pwd e dê enter para descobrir quem é o diretório corrente. Use o comando ls para listar o conteúdo desse diretório.

  3. Crie um diretório para seus programas de inf1018. Use o comando mkdir inf1018 para isso. Em seguida, dê cd inf1018 e volte a usar o comando pwd para verificar qual é, agora, o diretório corrente.

  4. Compile e execute o seguinte programa:
    
    #include <stdio.h>
    #include <stdlib.h>
    
    float foo (float pf) {
      return pf+1;
    }
    
    int bar (int pb) {
      return pb+1;
    }
    
    int main (int argc, char **argv) {
      int i; float f;
      if (argc!=3) {
        printf ("uso do programa: %s <int> <float>\n", argv[0]);
        exit(0);
      }
      i = atoi(argv[1]);
      f = atof(argv[2]);
      printf ("bar(%d): %d \nfoo(%.2f): %.2f\n",
              i, bar(i), f, foo(f));
      return 0;
    }
    
    
    Para compilá-lo, abra uma janela de editor (Accessories->Text Editor), recorte e cole o código anterior, e salve o programa em um arquivo aula1.1.c na pasta inf1018. Volte ao terminal e execute o comando abaixo:
    gcc -Wall -o aula1.1 aula1.1.c
    Para executar o resultado, use:
    ./aula1.1 2 4

    Obs: A opção -Wall diz ao gcc para gerar warnings (avisos) e o argumento -o o instrui a colocar o resultado da compilação, o programa executável, no arquivo cujo nome vem a seguir: aula1.1 Você irá usar isso durante o curso inteiro, então por favor tente entender essa linha de comando.

    Tente executar seu programa com
    ./aula1.1 2
    Veja o que acontece. Leia o código e tente entender como o programa funciona. argc e argv são argumentos de main que capturam o que foi digitado na linha de comando. argc é o número de itens digitados e argv um array de strings com cada um dos itens!

  5. Vamos agora dividir nosso programa em dois arquivos. Crie um outro arquivo, labaux.c, e copie para ele as funções foo e bar. Substitua as funções, no arquivo aula1.1.c, por seus cabeçalhos: float foo (float pf); int bar (int pb); e salve-o como aula1.2.c. Agora seu programa é composto por 2 arquivos .c. Para criar o executável, cada um deles é traduzido para um arquivo objeto pelo compilador e depois o ligador junta esses dois objetos. Depois de cada passo abaixo, use o comando ls para ver que arquivo foi criado.
    1. compilação labaux.c:
       gcc -Wall -c labaux.c 
    2. compilação aula1.2.c:
       gcc -Wall -c aula1.2.c 
    3. ligação dos objetos:
       gcc -o aula1.2 labaux.o aula1.2.o
    Na realidade, você pode fazer tudo isso de uma vez usando:
    gcc -Wall -o aula1.2 labaux.c aula1.2.c
    (avisando ao compilador que o seu programa é composto por esses dois arquivos .c)

    Teste novamente o programa (agora aula1.2).

  6. Vamos agora experimentar fazer essa mesma compilação sem os cabeçalhos declarados no arquivo que contém a main. Crie um arquivo aula1.3.c similar a aula1.2.c mas sem os cabeçalhos de bar e foo. Compile usando
    gcc -Wall -o aula1.3 labaux.c aula1.3.c
    (experimente também
    gcc -o aula1.3 labaux.c aula1.3.c
    para ver a diferença) O compilador gera algumas mensagens precedidas da palavra warning. Esses são alertas, que o programador deve ler com cuidado, por indicarem possíveis erros, mas que não impedem o compilador de gerar o programa executável. Teste novamente o programa resultante:
    ./aula1.3 2 4
    O que aconteceu? O que mudou? Como tiramos a informação sobre as funções do arquivo, o compilador não consegue gerar o código corretamente... Vamos entender isso ao longo do curso.

  7. Nosso programa também contém chamadas às funções printf, atoi e atof. Como o compilador sabe como são essas funções? Esse é o papel dos #include no início do arquivo. As diretivas # são tratadas pelo pre-processador, que atua antes do compilador. Para ver o que o pre-processador faz, crie o arquivo aula1.4.c com o código abaixo:
    
    #include <stdio.h>
    #define VEZES 10
    
    int main (void) {
      int i;
      for (i=0;i<VEZES;i++)
        printf ("alo alo!\n");
      return 0;
    }
    
    Use o comando
    gcc -E aula1.4.c >prepro.c 
    para fazer com que o gcc execute apenas o pre-processador, e jogue a saída no arquivo prepro.c. Abra o arquivo. Vá no final do arquivo e veja como está agora o for. O que o preprocessador fez com o nome VEZES? A outra diretiva processada foi o #include <stdio.h>. Essa diretiva faz com que o pre-processador inclua textualmente o arquivo <stdio.h>, com informação sobre printf. Que informação é essa? Procure a função printf no arquivo gerado. O código dela está nesse arquivo?