Entwurfsprinzipien, Best Practices und Entwurfsmuster für C (oder prozedurale Programmierung im Allgemeinen)? [geschlossen]

91

Gibt es bekannte Entwurfsprinzipien, Best Practices und Entwurfsmuster, denen man beim Entwerfen eines C-Projekts folgen kann? Oder nützliche Gestaltungsprinzipien für die prozedurale (imperative) Programmierung im Allgemeinen?

(Ich bin ein Kind der 'objektorientierten Generation' und muss zum ersten Mal ein großes C-Projekt entwerfen.)

Dimi
quelle
1
Sie könnten an Antworten auf diese Frage interessiert sein: stackoverflow.com/questions/661307/…
mouviciel
7
Ich habe einige Internet- und Universitätsbibliotheksrecherchen durchgeführt, bevor ich meine Frage gestellt habe, und war definitiv nicht mit Büchern über Software-Design für C überfordert. Ich frage Sie nach Ihrem Favoriten (nicht über allgemeine C-Bücher, nicht über Codierungskonventionen wie sinnvolle Variablen Namen, aber über eine höhere Abstraktion, Software-Architektur-Ebene). Darüber hinaus stimme ich Ihrem Vorwurf, auf andere Menschen angewiesen zu sein, nicht zu. Sie meinen, jeder Programmierer sollte sich selbst über Best Practices und gute Designmuster informieren? Dies ist mit Sicherheit eine Frage, bei der die Erfahrungen anderer genutzt werden müssen.
Dimi
2
Entschuldigung, Dimi, hier ging es nicht speziell um dich, und ich war mir nicht ganz sicher. Dieses Zeug wurde früher genauso mündlich weitergegeben wie auf jede andere Weise: Es gab keine nominellen offiziellen "Muster", Jonathons Antwort war das, was man in den Büchern finden würde, aber jeder wusste, dass sich Informationen verstecken. Es scheint, dass die mündliche Überlieferung verloren geht, und viele junge Programmierer glauben, dass OOP die Kapselung und Trennung erfunden hat. Diese Gemeinschaft scheint weniger Sinn für ihre eigene Geschichte zu haben, als ich gerne sehen würde. So meine Bestätigung, dass ich mich in einem mürrischen Gebiet für alte Männer befinde.
dmckee --- Ex-Moderator Kätzchen
1
Ich kann Ihre Rückschau nicht teilen, da ich nur meine Füße auf dem Feld finde, aber ich akzeptiere Ihren Vorschlag. Vielen Dank, dass Sie sich klarer ausdrücken, immer von großem Wert, um die Ansicht einer erfahrenen Person lesen zu können. Ich schätze Ihren Beitrag sehr.
Dimi
Der SEI CERT C-Codierungsstandard bietet eine Reihe guter Regeln und allgemeiner bewährter Verfahren sowie Dinge, die Sie vermeiden sollten.
Rami

Antworten:

65

Verstecken von Informationen - wie von Parnas ( Software Fundamentals ) unterstützt.

Sorgfältige Verwaltung von Headern und Sichtbarkeit:

  • Alles in einer Quelldatei, das vor der Außenwelt verborgen werden kann, sollte sein; Nur die dokumentierte externe Schnittstelle sollte freigelegt werden.
  • Alles, was verfügbar gemacht wird, wird in einem Header deklariert.
  • Dieser Header wird dort verwendet, wo die Funktionalität benötigt wird (und wo sie definiert ist).
  • Der Header ist in sich geschlossen - wenn Sie ihn benötigen, verwenden Sie ihn und müssen sich keine Gedanken darüber machen, welche anderen Header ich ebenfalls einschließen muss, da der Header sicherstellt, dass er funktioniert, indem er alles enthält, was er benötigt, um ihn zu erstellen Arbeit.
  • Der Header ist selbstgeschützt - es spielt also keine Rolle, ob er mehrmals enthalten ist.

    #ifndef HEADER_H_INCLUDED
    #define HEADER_H_INCLUDED
    ...rest of header contents, including other #include lines if necessary
    #endif /* HEADER_H_INCLUDED */
    
  • Entwerfen Sie Funktionssätze, um an 'Objekten' (normalerweise Strukturen) zu arbeiten - und verwenden Sie diese Funktionen, anstatt die Innereien der Struktur in dem Code zu durchsuchen, der sie verwendet. Betrachten Sie es als selbst auferlegte Kapselung.

Jonathan Leffler
quelle
Guter Punkt, danke, Jonathan. Abstrakte Datentypen sind ein weiteres gutes Beispiel für das Verstecken von Informationen mit einer sauberen Trennung von Nutzung und Implementierung (bekannte externe Schnittstelle und unbekannte interne Implementierung).
Dimi
23

Meine drei Ratschläge:

  • Schreiben Sie Unit-Tests. Sie helfen Ihnen dabei, ein Design zu finden, das Ihrem Problem im Laufe der Zeit entspricht. Viel besser, als sich (ausschließlich) auf vorher meditiertes Denken zu verlassen.
  • Lassen Sie einen Speicherleckdetektor (es gibt alle Arten von Bibliotheken) vom ersten Tag an installieren und ausführen. Lassen Sie diese Bibliothek alle Lecks ausdrucken, sobald das Programm / die Tests beendet werden. Auf diese Weise können Sie ein Leck erkennen, sobald Sie es einführen, wodurch die Fixierung weniger schmerzhaft wird.
  • Schreiben Sie OOP-Code in C. Nicht so schwierig. Es ist zwar möglich, das Überschreiben von Methoden zu emulieren, ich empfehle jedoch, mit der Emulation einfacher Objekte zu beginnen. Selbst dieser einfache Mechanismus kann Ihnen eine große Kilometerleistung bringen.

Hier ist ein Beispiel:

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
quelle
Danke, Itay. Ich werde Ihren Ratschlägen folgen.
Dimi
1
4. Wirf das Ergebnis von nicht malloc.
SS Anne
22

Es gibt ein gutes, kostenloses Online-Buch mit dem Titel Objektorientierte Programmierung mit ANSI-C , das das Thema des Schreibens von objektorientiertem Code in C behandelt. Eine Google-Suche nach "objektorientiertem C" liefert auch eine Reihe anderer Vorteile Beispiele und Ressourcen.

Wenn Ihr Projekt sicherheitskritisch ist, ist MISRA-C ein gutes Regelwerk. Es ist hauptsächlich für Embedded C gedacht, kann aber auch in anderen Bereichen nützlich sein.

Ich betrachte mich als OO-Codierer und arbeite viel mit Embedded-C. Der beste Rat, den ich geben kann, insbesondere bei großen Projekten, ist, es nicht zu übertreiben. Das Erstellen eines vollständigen OO-Frameworks auf ANSI C kann sehr verlockend sein, erfordert jedoch viel Zeit und Mühe, um es richtig zu machen. Je ausgefallener Sie werden, desto mehr Zeit verbringen Sie mit dem Debuggen Ihres Frameworks, anstatt am eigentlichen Projekt zu arbeiten. Gehen Sie die Aufgabe mit einem klaren Kopf und einem guten, soliden Verständnis von YAGNI an . Viel Glück!

James
quelle
Vielen Dank, e.James. Ich möchte kein objektorientiertes Framework über ANSI C erstellen, sondern nach speziellen und geeigneten Prinzipien für das prozedurale Programmierdesign suchen. Der MISRA-C-Hinweis ist sehr nützlich, insbesondere weil es sich tatsächlich um ein eingebettetes Projekt handelt. Ich werde es mir genauer ansehen.
Dimi
Ah, die Freuden von Embedded C. Vergessen Sie nicht, dass Sie Ihre Variablen oben in Ihrer Funktion (oder oben in einem { }Block) deklarieren müssen . Dieser beißt mich immer ein oder zwei Mal:)
e.James
7

OOP ist eine Methodik, keine Technologie. Mein erster Rat ist also, es nicht mehr als prozedurale Programmierung zu betrachten.

In Bezug auf e.James möchten Sie nicht versuchen, eine objektorientierte Sprache neu zu erstellen oder so zu tun, als hätten Sie die entsprechenden Funktionen. Sie können immer noch alles richtig machen, indem Sie sich an ein paar einfache Prinzipien halten:

  1. Testen Sie alles.
  2. Finden Sie, was variiert, und kapseln Sie es.
  3. Design zu Schnittstellen.

quelle