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
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
structmy_struct{
2
intWertA;/* soll public sein */
3
intWertB;/* 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
structmy_struct{
2
intWertA;
3
structmy_struct_private{
4
intWertB;
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
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:
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.
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.