Regras de programação em C

Apresentam-se de seguida algumas regras a seguir pelos alunos desta cadeira na escrita de programas C, e que devem ser seguidas em todos os trabalhos que apresentarem, de modo a garantir igual comportamento dos programas independentemente do compilador e/ou sistema operativo utilizado.

  1. O código produzido deve seguir a norma ANSI-C (ver, por exemplo, "The C Programming Language" [segunda edição], B. Kernighan e D. Ritchie, Prentice Hall, 1988).
  2. Não se devem usar caracteres portugueses nos programas, pois a norma ANSI-C não os permite senão dentro de cadeias de caracteres. Nem mesmo nos comentários são aceitáveis. E, como o MS-DOS usa os seus próprios códigos, também não são aconselháveis nas cadeias de caracteres, pois os programas mostram caracteres diferentes, errados, quando executados noutros ambientes (outros sistemas operativos).
  3. Não se deve utilizar a função gets() nunca, pois não permite limitar o número de caracteres lidos, potenciando assim a corrupção da memória quando se excede o limite da cadeia de caracteres passada como argumento. Utilize-se fgets().
  4. A função feof() não indica, como o nome pode dar a entender, se a posição de leitura/escrita se encontra no fim do ficheiro, mas sim se já se tentou efectuar alguma leitura, sem sucesso, para além do fim do ficheiro.
  5. Devem-se evitar todas as chamadas a funções que não façam parte das bibliotecas da norma ANSI-C, tais como getch(), clrscr() e gotoxy().
  6. Deve-se evitar tanto quanto possível incluir ficheiros de cabeçalho que não sejam previstos pela norma ANSI-C, por exemplo conio.h.
  7. Devem-se evitar tanto quanto possível as chamadas a funções duma forma não prevista na norma ANSI-C. Por exemplo, a norma especifica que o comportamento de fflush() quando aplicada a um canal aberto para leitura é indefinido, devendo-se por isso substituir a chamada fflush(stdin) (definida no TC) por chamadas a uma função semelhante a mataLinha():
    void mataLinha(void)
    
    {
        int c;
        
        while((c = getchar()) != '\n' && c != EOF)
            /* Nada. */;
    }
    
  8. Não se devem usar comentários à C++, i.e., desde // até ao fim da linha.
  9. É extremamente útil tomar atenção a todos os avisos emitidos pelo compilador: são todos relevantes.
  10. A maior parte das funções devolvem valores relevantes, e é vantajoso usá-los (e.g., a função scanf() devolve o número de argumentos lidos com sucesso ou EOF caso o fim do ficheiro seja atingido).
  11. A função main() deve ser definida sempre como devolvendo um int, que é um valor que indica o sucesso ou não do programa. Usar sempre as macros EXIT_SUCCESS e EXIT_FAILURE nas instruções return da função main(), macros essas definidas em stdlib.h.
  12. A função exit() deve ser chamada sempre com argumento EXIT_SUCCESS ou EXIT_FAILURE, de modo a assinalar o sucesso ou falhanço do programa.
  13. Uma função f() sem argumentos e devolvendo valores int deve ser declarada/definida da seguinte forma:
    int f(void)
    e nunca 
    /* ERRADO */
    int f()
    
  14. Uma função f() não devolvendo qualquer valor deve ser declarada/definida da seguinte forma:
    void f(/* parametros... */)
    e nunca 
    /* ERRADO */
    f(/* parametros */)
    e muito menos 
    /* ERRADO */
    f()

    pois, se é verdade que em alguns casos tais práticas não trazem quaisquer problemas, muitas vezes o comportamento dos programas torna-se imprevisível. Por exemplo, por que é que

    #include <stdio.h>
    #include <stdlib.h>
    
    double quadrado1();           /* INCORRECTO! */
    double quadrado2(double);     /* CORRECTO. */
    
    int main(void) {
        printf("teste1: 11*11 = %g?\n", quadrado1(11));
        printf("teste2: 11*11 = %g?\n", quadrado1(11.0));
        printf("teste3: 11*11 = %g?\n", quadrado2(11));
        printf("teste4: 11*11 = %g?\n", quadrado2(11.0));
        return EXIT_SUCCESS;
    }
    
    double quadrado1(double x) {
        return x*x;
    }
    
    double quadrado2(double x) {
        return x*x;
    }

    imprime

    teste1: 11*11 = 3.98585?
    teste2: 11*11 = 121?
    teste3: 11*11 = 121?
    teste4: 11*11 = 121?

    em que o primeiro valor pode variar consoante a máquina e o compilador utilizado?

  15. As instruções ponteiro == 0 e ponteiro == NULL têm exactamente o mesmo significado, pois a macro NULL está definida como 0, 0L ou (void*)0, dependendo do ambiente.

Página concebida e mantida por Eng. Manuel Menezes de Sequeira (última actualização 2006/07/07)
Copyright © 1996-2001 ISCTE