Princípios de design, melhores práticas e padrões de design para C (ou programação de procedimentos em geral)? [fechadas]

91

Existem princípios de design, práticas recomendadas e padrões de design conhecidos que alguém pode seguir ao projetar um projeto C? Ou princípios de design úteis para programação procedural (imperativa) em geral?

(Sou filho da 'geração orientada a objetos' e tenho que criar um grande projeto C pela primeira vez)

Dimi
fonte
1
Você pode estar interessado em respostas para esta pergunta: stackoverflow.com/questions/661307/…
mouviciel
7
Eu fiz algumas pesquisas na Internet e na biblioteca da universidade, antes de postar minha pergunta, e definitivamente não fiquei sobrecarregado com livros sobre design de software para C. Peço a você qual é o seu favorito (não falando sobre livros C gerais, não falando sobre convenções de codificação como variáveis ​​significativas nomes, mas sobre uma abstração superior, nível de arquitetura de software). Além disso, não concordo com a sua censura de 'depender de outras pessoas'. Você quer dizer que cada programador deve descobrir por si mesmo sobre as melhores práticas e bons padrões de design? Esta é com certeza uma questão sobre a qual a experiência do outro deve ser usada.
Dimi
2
Desculpe, Dimi, isso não era sobre você em particular, e eu não fui muito claro. Essas coisas costumavam ser transmitidas tanto pela tradição oral quanto por qualquer outro meio: não havia um conjunto nominal de "Padrões" oficiais, a resposta de Jonathon era o que você encontraria nos livros, mas todos sabiam sobre ocultação de informações. Parece que a tradição oral está se perdendo, e muitos jovens programadores pensam que OOP inventou o encapsulamento e a separação. Esta comunidade parece ter menos noção de sua própria história do que eu gostaria de ver. Daí o meu reconhecimento de que estou no território do velho rabugento.
dmckee --- ex-gatinho moderador,
1
Não posso compartilhar sua visão retrospectiva, uma vez que acabei de encontrar meus pés no campo, mas aceito sua sugestão. Obrigado por se expressar com mais clareza, sempre de grande valor para poder ler a visão de uma pessoa experiente. Eu realmente aprecio sua contribuição.
Dimi
O Padrão de Codificação SEI CERT C fornece um bom conjunto de regras e boas práticas comuns , bem como coisas que você deve tentar evitar usar.
Rami,

Respostas:

65

Esconder informações - conforme defendido por Parnas ( Fundamentos de Software ).

Gerenciamento cuidadoso de cabeçalhos e visibilidade:

  • Tudo em um arquivo de origem que pode ser escondido do mundo externo deve ser; apenas a interface externa documentada deve ser exposta.
  • Tudo o que é exposto é declarado em um cabeçalho.
  • Esse cabeçalho é usado onde a funcionalidade é necessária (e onde é definida).
  • O cabeçalho é independente - quando você precisa dele, você o usa e não precisa se preocupar com 'quais outros cabeçalhos eu também tenho que incluir' porque o cabeçalho garante que funcione incluindo tudo o que for necessário para torná-lo trabalhos.
  • O cabeçalho é autoprotegido - portanto, não importa se ele é incluído várias vezes.

    #ifndef HEADER_H_INCLUDED
    #define HEADER_H_INCLUDED
    ...rest of header contents, including other #include lines if necessary
    #endif /* HEADER_H_INCLUDED */
    
  • Projete conjuntos de funções para trabalhar em 'objetos' (geralmente estruturas) - e use essas funções em vez de vasculhar as entranhas da estrutura do código que a está usando. Pense nisso como um encapsulamento autoimposto.

Jonathan Leffler
fonte
Bom ponto, obrigado, Jonathan. Os tipos de dados abstratos são outro bom exemplo de ocultação de informações com uma separação clara de uso e implementação (interface externa conhecida e implementação interna desconhecida).
Dimi
23

Meus três conselhos:

  • Escreva testes de unidade. Eles o ajudarão a encontrar um projeto que se adapte ao seu problema conforme você avança. Muito melhor do que confiar (somente) no pensamento pré-meditado.
  • Tenha um detector de vazamento de memória (existem todos os tipos de bibliotecas por aí) instalado e funcionando desde o primeiro dia. Faça com que esta biblioteca imprima todos os vazamentos assim que o programa / testes forem encerrados. Isso permitirá que você pegue um vazamento assim que introduzi-lo, tornando sua fixação muito menos dolorosa.
  • Escreva o código OOP em C. Não é tão difícil. Embora seja possível emular a substituição de método, sugiro que você comece com a emulação de objetos simples. Até mesmo esse mecanismo simples pode fornecer uma grande quilometragem.

Aqui está um exemplo:

typedef struct Vector {
  int size;
  int limit;
  int* ints; 
} Vector;

Vector* Vector_new() {
  Vector* res = (Vector*) malloc(sizeof(Vector));
  res->limit = 10;
  res->size = 0;
  res->ints = (int*) malloc(sizeof(int) * res.limit);

  return res;
}


void Vector_destroy(Vector* v) {
  free(v->ints);
  free(v);
}

void Vector_add(Vector* v, int n) {
  if(v->size == v->limit) {
    v->limit = v->limit * 2 + 10;
    v->ints = realloc(v->ints, v->limit);     
  }

  v->ints[v->size] = n;
  ++v->size;
}

int Vector_get(Vector* v, int index) {
  if(index >= 0 && index < v->size)
    return v->ints[index];

  assert false;
}
Itay Maman
fonte
Obrigado, Itay. Vou seguir seus conselhos.
Dimi
1
4. Não lance o resultado de malloc.
SS Anne
22

Há um bom livro online gratuito, intitulado Programação Orientada a Objetos com ANSI-C , que cobre o tópico de escrever código orientado a objetos em C. Uma pesquisa no Google por "C orientado a objetos" também resulta em vários outros bons exemplos e recursos.

Se o seu projeto é crítico para a segurança, MISRA-C é um bom conjunto de regras. Ele se destina principalmente a c embutido, mas também pode ser útil em outras áreas.

Eu me considero um codificador OO e faço muitos trabalhos com C incorporado. O melhor conselho que posso dar, especialmente para grandes projetos, é não exagerar. Criar uma estrutura OO completa com base no ANSI C pode ser muito tentador, mas é preciso muito tempo e esforço para acertar. Quanto mais sofisticado você fica, mais tempo vai gastar depurando seu framework em vez de trabalhar no projeto real . Aborde a tarefa com a cabeça limpa e um bom e sólido conhecimento do YAGNI . Boa sorte!

e.James
fonte
Obrigado, e.James. Não quero criar uma estrutura orientada a objetos em cima do ANSI C, mas procuro princípios de design de programação procedural apropriados e especiais. A dica MISRA-C é muito útil, especialmente porque na verdade é um projeto incorporado. Eu vou dar uma olhada nisso.
Dimi
Ah, as alegrias do C. embutido. Não se esqueça de que você deve declarar suas variáveis ​​no topo de sua função (ou no topo de qualquer { }bloco). Aquele sempre me morde uma ou duas vezes:)
e.James
7

OOP é uma metodologia, não uma tecnologia. Portanto, meu primeiro conselho é parar de pensar nisso como programação procedural.

Para o ponto de e.James, você não quer tentar recriar uma linguagem orientada a objetos ou fingir que tem os recursos para isso. Você ainda pode fazer todas as coisas certas se apegando a alguns princípios simples:

  1. Teste tudo.
  2. Descubra o que varia e encapsule-o.
  3. Design para interfaces.

fonte