Hallo! Ich habe hier ein paar Fragen zum Organisieren, Strukurieren, etc. von extra Files (.c, .h). Derzeit verwende ich als IDE Atmel Studio 7 und würde meine Projekte gerne aufteilen. Funktioniert alles gut nur kann ich mich nicht einigen wie ich die Files mit extra Ordnern aufteilen will/soll und außerdem wie ich struct's für diese Header gestalte. 1. Projektaufteilung Um das Programm übersichtlich zu halten würde ich gerne Unterornder erstellen. Macht das noch jemand und wie teilt ihr diese auf? Erfundenes Beispiel: Robotor mit einem Motor mit Encoder und H-Brücke (Geschwindigkeit abhängig von Distanz), Distanzsensor, LED, I2C Digital-Widerstand vor LED und abhängig von Distanz, serielle Schnittstelle zu PC für Informationen. Nun wie könnte man soetwas aufteilen? Nach Katogorie, Anwendung, ...? Kategorie dann z.B. Ordner wie "Aktor" (Motor bzw. Motortreiber, LED), "Sensor" (IR-Distanzsensor, Motorencoder), "Kommunikation" (I2C, UART)? Oder vielleicht nach Anwendung "Motor" (Motortreiber, Motorencoder), "LED" (LED, Widerstand), "Distanz" (IR-Distanzsensor) und "Info" (UART). Oder sonstige Vorschläge? Macht ihr solche Einteilungen überhaupt? 2. Struct's in Header Wenn private Variablen in einer Struct vorhanden sind, will ich doch eigentlich, dass sie außerhalb (der dazugehörigen .c File) nicht bearbeitet werden soll. Also könnte ich das mit struct's in der spezifischen .c File einbauen. Es müssen aber diese privaten Struct's mit den "public" Struct's erstellt werden, was aber ohne malloc/free schwierig ist. Eine weitere Möglichket wäre während Compiletime einen definierten Array von diesen Struct's erstellen, auch nicht gerade die beste Lösung. Gibt es dazu eine solide Lösung oder doch lieber dabei bleiben, alles in eine Struct zu packen und im Main-Code diese Struct dann initialisieren? Falls diese Themen evtl. auch in C-Style Guides o.Ä. angesprochen werden, wäre ich auch dankbar über eine Verlinkung. Ich will eigentlich nur eine Richtlinie an die ich mich halten kann. mfg Scheams
:
Verschoben durch User
Christoph A. schrieb: > Hallo! > > Ich habe hier ein paar Fragen zum Organisieren, Strukurieren, etc. von > extra Files (.c, .h). > > Derzeit verwende ich als IDE Atmel Studio 7 und würde meine Projekte > gerne aufteilen. Funktioniert alles gut nur kann ich mich nicht einigen > wie ich die Files mit extra Ordnern aufteilen will/soll und außerdem wie > ich struct's für diese Header gestalte. > > 1. Projektaufteilung > Um das Programm übersichtlich zu halten würde ich gerne Unterornder > erstellen. Macht das noch jemand und wie teilt ihr diese auf? Natürlich. Man kann die Unterteilung zum Beispiel anhand von hinreichend großen Subsystemen vornehmnen. Verschiedene Funktionalitäten innerhalb des gleichen Subsystems kann man zum Beispiel auf verschiedene Dateien innerhalb des gleichen Unterverzeichnisses verteilen. > 2. Struct's in Header > Wenn private Variablen in einer Struct vorhanden sind, will ich doch > eigentlich, dass sie außerhalb (der dazugehörigen .c File) nicht > bearbeitet werden soll. C kennt keine privaten Variablen innerhalb von structs. Du kannst Variablen innerhalb einer C-Datei (aber außerhalb jeder Funktion in dieser Datei) als "static" deklarieren. Dann kann auf diese Variable nur innerhalb dieser Übersetzungseinheit zugegriffen werden.
Christoph A. schrieb: > 1. Projektaufteilung Alles was universell verwendbar ist, wandert in den lib Ordner. Dazu zählen auch z.B. I2C, UART, FIFOs, sonstige Bibliotheken. Also alles, was man unverändert in anderen Projekten verwenden kann. Den Rest, also alles projektspezifische, teile ich nach gutdünken in logische Blöcke auf. Christoph A. schrieb: > 2. Struct's in Header Ich sehe, ausser bei ganz einfachen Dingen, alle Member als privat an und bearbeite diese nur über entsprechende Funktionen. Zum Erstellen der Strukturen verwende ich ebenfalls eigene Funktionen (ähnlich den Konstruktoren in C++). Die Member stehen dann trotzdem als public im Header, aber mit genügend Disziplin sollte das nicht mehr stören, da alles über die Funktionen erledigt wird.
Be S. schrieb: > Christoph A. schrieb: >> 2. Struct's in Header > > Ich sehe, ausser bei ganz einfachen Dingen, alle Member als privat an > und bearbeite diese nur über entsprechende Funktionen. Zum Erstellen der > Strukturen verwende ich ebenfalls eigene Funktionen (ähnlich den > Konstruktoren in C++). Die Member stehen dann trotzdem als public im > Header, aber mit genügend Disziplin sollte das nicht mehr stören, da > alles über die Funktionen erledigt wird. Hm, wozu dann noch die Deklaration im Header? Alles, was nicht von außerhalb einer C-Datei zugreifbar sein soll, braucht auch nicht in der zugehörigen Header-Datei zu stehen.
Mark B. schrieb: > Hm, wozu dann noch die Deklaration im Header? > > Alles, was nicht von außerhalb einer C-Datei zugreifbar sein soll, > braucht auch nicht in der zugehörigen Header-Datei zu stehen. Ja, das ist klar. Folgendes Beispiel:
1 | struct my_struct{ |
2 | int WertA; /* soll public sein */ |
3 | int WertB; /* soll private sein */ |
4 | };
|
Nun kannst du niemanden davon abhalten, auf WertB zuzugreifen, obwohl er es nicht sollte. Sinnvoll lässt sich das ohne malloc und void-Zeiger nicht trennen. Deswegen mein Vorschlag, einfach alle Member "private" zu machen und alle Zugriffe über Funktionen zu erledigen. Man kann zwar trotzdem auf die Member zugreifen, aber die eigene Disziplin soll es verhindern. Eine andere Möglichkeit wäre:
1 | struct my_struct{ |
2 | int WertA; |
3 | struct my_struct_private{ |
4 | int WertB; |
5 | }Private; |
6 | };
|
So wird verdeutlicht, das public und was private ist.
Erstmal danke für die schnellen Antworten :) Be S. schrieb: > Alles was universell verwendbar ist, wandert in den lib Ordner. Dazu > zählen auch z.B. I2C, UART, FIFOs, sonstige Bibliotheken. Also alles, > was man unverändert in anderen Projekten verwenden kann. Gefällt mir schon einmal gut! :) Ihr habt Aufteilung nach Subsysteme bzw. logische Blöcke angesprochen aber was ist das für euch? Ich schwanke immer mit meinen Gedanken, dass einerseits die Aufteilung z.B. nach Kategorie, andererseits nach Anwendung ihre jeweiligen Vorteile haben. Vielleicht könntet ihr ein Beispiel geben, anhand meines zuvor genanntes erfundens Projekt oder allgemein (mit Ordnernamen)? Würde mir sicher helfen :) Be S. schrieb: > Ich sehe, ausser bei ganz einfachen Dingen, alle Member als privat an > und bearbeite diese nur über entsprechende Funktionen. Zum Erstellen der > Strukturen verwende ich ebenfalls eigene Funktionen (ähnlich den > Konstruktoren in C++). Die Member stehen dann trotzdem als public im > Header, aber mit genügend Disziplin sollte das nicht mehr stören, da > alles über die Funktionen erledigt wird. D.h. im Main-Code erstellst du dann eine struct und übernimmst/-gibst diese dann immer in die Funktionen? Für die Initialisierung ebenfalls (wenn ich das richtig verstanden habe). Was ist wenn ich eine struct für z.B. einen PID Regler habe, wo dann recht viele Initialisierungswerte benötigt werden (mit div. Extras upto 15). Diese als Funktionsparameter zu übergeben ist vielleicht nicht die "feinste" Art. Initialisierst du diese vielleicht dann doch direkt in der struct Initialisierung? mfg Scheams
:
Bearbeitet durch User
Christoph A. schrieb: > D.h. im Main-Code erstellst du dann eine struct und übernimmst/-gibst > diese dann immer in die Funktionen? Für die Initialisierung ebenfalls > (wenn ich das richtig verstanden habe). Richtig. Hier ein Beispiel:
1 | struct my_struct{ |
2 | int WertA; |
3 | int WertB; /* geht den Anwender nix an */ |
4 | };
|
5 | |
6 | |
7 | struct my_struct my_struct_init(int WertA){ |
8 | return (struct my_struct){WertA, 42}; |
9 | }
|
10 | |
11 | |
12 | int my_struct_get_a(struct my_struct * Struct){ |
13 | return Struct->WertA; |
14 | }
|
15 | |
16 | |
17 | void my_struct_do_something(struct my_struct * Struct){ |
18 | Struct->WertA *= 2; |
19 | Struct->WertB++; |
20 | }
|
21 | |
22 | |
23 | int main(void){ |
24 | struct my_struct Alt = {123, 42}; |
25 | struct my_struct Neu = my_struct_init(123); |
26 | |
27 | Alt.WertA *= 2; |
28 | Alt.WertB++; |
29 | my_struct_do_something(&Neu); |
30 | |
31 | int X = Alt.WertA; |
32 | int Y = my_struct_get_a(&Neu); |
33 | |
34 | return 0; |
35 | }
|
Sieht auf den ersten Blick umständlich und aufgebläht aus. Hat aber den Vorteil, dass du Funktionalität kapselst und so Änderungen einfacher durchführen kannst. Du kannst das gesamte Modul über den Haufen werfen und neu programmieren, solange sich das Modul gleich verhält wie vorher, musst du nichts anderes anpassen. Bei direktem Zugriff auf Member muss sich nur ein Datentyp in der Struktur ändern und du musst im schlimmsten an zig Stellen in deinem Programm Anpassungen oder Prüfungen vornehmen. Das war dann auch der Punkt, wo ich auch für kleine uCs auf C++ umgestiegen bin, da die Sprache dieses Vorgehen stark vereinfacht. Bringt aber viele, eher sehr viele, neue und andere Dinge hinzu, die das Leben nicht unbedingt vereinfachen. EDIT: Nicht falsch verstehen, ich mache das nicht immer so, nur meistens. Für eine Struktur, die nur Werte halten muss (z.B. RGB-Farben), treibe ich diesen Aufwand nicht.
:
Bearbeitet durch User
Be S. schrieb: > Alles was universell verwendbar ist, wandert in den lib Ordner. Dazu > zählen auch z.B. I2C, UART, Ach.. Das möchte ich sehen. Nach meiner Erfahrung sind gerade Peripherie-Treiber eben nicht universell verwendbar, dank unterschiedlicher Interruptvektoren und anderer Kleinigkeiten. Das Einzige, was da universell ist bzw. bei MIR so universell wie möglich gestaltet wird, ist die Schnittstelle des Treibers zu den Anwendungsschichten, als kurz: das Headerfile. Und eben diese Schnittstelle sorgt dafür, daß die höheren Programmebenen weitestgehend unabhängig sind von dem konkreten Controller, so daß man zum Portieren sich fast nur die Peripherie-treiber vorknöpfen muß. Ansonsten gönne ich mir für jedes Projekt ein völlig separates Directory, damit eventuell nötige Anpaßarbeiten nicht auf andere Projekte durchschlagen. W.S.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.