Lowlevel
Lowlevel => OS-Design => Thema gestartet von: Liam am 14. October 2009, 12:12
-
Hallo,
ich habe bisher einiges durch das "Henkes"-Tutorial gelernt und habe auch schon selber etwas experimentiert.
Jetzt möchte ich die nötigen Tools sammeln und die "Prerequisites" zusammenstellen.
Bisher kam ich auf ein UML-Modellierungsprogramm und ein Dokumentationsprogramm. (Doxygen vielleicht?)
Was brauche ich noch?
Wie soll ich da anfangen? Jetzt auch bezüglich Kernel-Design?
Was ist so der beste Einstieg?
Gruß
Liam
-
Was die Tools angeht, gibt es noch einen Abschnitt in unserer eigenen Tutorialreihe, die du zumindest überfliegen solltest, weil das die Grundlage ist, die wir gut kennen und auf die du dich bei Fragen beziehen kannst (und sei es nur, um zu erklären, was bei dir anders ist): http://lowlevel.brainsware.org/wiki/index.php/Teil_1_-_Entwicklungsumgebung.
Neben den Selbstverständlichkeiten wie Editor und Compiler, ist doxygen sicher keine schlechte Idee. git (oder wengistens Subversion) ist ein Muss.
Was das Design angeht, willst du vielleicht das hier lesen: http://lowlevel.brainsware.org/wiki/index.php/OS-Dev_für_Einsteiger#Der_eigentliche_Kernel
-
Kann ich git auch unter meinem cygwin nutzen, oder was gibt es da so?
Muss eine aktive Internetverbindung bestehen oder kann ich lokal an meinem vom Internet getrennten PC arbeiten?
-
Scheint es auch für Cygwin zu geben, aber die üblichere Variante ist msysgit (http://code.google.com/p/msysgit/), das auf mingw basiert. Gerade bei git arbeitest du grundsätzlich immer auf einem lokalen Repository und verbindest dich nur mit einem Rechner im Internet (git push/pull), wenn du gerade was veröffentlichen bzw. die aktuellen Änderungen runterladen möchtest.
-
Ich habe schon ein bisschen mit git und doxygen rumprobiert.
Bei git finde ich es momentan etwas umständlich andauernd nach einigen Änderungen einen commit zu veranlassen, aber ich denke mal, dass ich später froh darüber sein werde, wenn ich mal zurück in die Vergangenheit schauen kann.
Meine cygwin-git Version funktioniert einwandfrei und ich bin froh =)
Außerdem ist es etwas umständlich gewesen, die besonderen doxygen Kommentare, die nicht mein Coding-Stil sind einzufügen.
Ich hätte mal eine Frage: Ich möchte in doxygen auch meine (unkommentierten) Assembler Files in der File List haben. Gibt es einen Befehl auch deren Content da einzufügen? (Sorry für mein Denglisch. Ja, Denglisch xD)
Außerdem würde ich gerne für den Anfang an UNIX nah daranbleiben und ich habe mir gedacht (in meinen ersten Brainstormings), dass ich am besten einen Hybridkernel schreibe. Natürlich gibt es Vor- und Nachteile von monolithischen und Microkerneln, aber ich denke mal, dass man bei einem Hybriden die Vor- und Nachteile "intelligent" verpacken kann. Was denkt ihr darüber? (Besonders, die die schon an einem Projekt arbeiten: Wieso habt ihr euch für DEN Type eures Kernels entschieden?)
Was gibt es noch so an E-Paper/E-Book-Literatur, die sich mit OSDev beschäftigt? Einige Dinge, wie zum Beispiel A20 oder PM habe ich noch nicht zu 100% verstanden und ich will mich davor komplett informieren. Zwar habe ich schon einige Tutorials und dokumentative "Vade Mecum"s o.ä., aber mehr kann ja nicht schaden =)
Ansonsten werde ich mich hier durchs Wiki lernen.
@EDIT: Eine Frage habe ich noch. Ich würde gerne zu lerntechnischen Zwecken das Rad neu erfinden und würde gerne ein eigenes Dateisystem (mit Format) erfinden und nicht vorhandene Dateitypen, wie z.B. PDF, unterstützen. Dies ist zwar nicht effektiv und nicht unbedingt intelligent, aber ich will es gerne lernen, wie es ist ALLES selber zu machen. Was denkt ihr darüber?
-
Ich habe schon ein bisschen mit git und doxygen rumprobiert.
Bei git finde ich es momentan etwas umständlich andauernd nach einigen Änderungen einen commit zu veranlassen, aber ich denke mal, dass ich später froh darüber sein werde, wenn ich mal zurück in die Vergangenheit schauen kann.
Wirst du definitiv. Vor allem, wenn du mal größere Sachen umbaust und dabei was kaputtmachst, wirst du froh sein, die letzten Änderungen ganz oder teilweise wieder rückgängig machen zu können. Wenn in einer alten Version etwas funktioniert hat und in einer neueren tut es nicht mehr, kannst du genau zurückverfolgen, welche Änderung schuld war. Und so weiter.
Natürlich gibt es Vor- und Nachteile von monolithischen und Microkerneln, aber ich denke mal, dass man bei einem Hybriden die Vor- und Nachteile "intelligent" verpacken kann.
Dazu kann man wenig sagen. Du hast die Extreme Monolith und Mikrokernel, und alles andere, was dazwischen liegt, sind Hybride - sowohl Fast-Monolithen als auch Fast-Mikrokernel. Der Begriff sagt also erst einmal nicht sehr viel aus.
Einige Dinge, wie zum Beispiel A20 oder PM habe ich noch nicht zu 100% verstanden und ich will mich davor komplett informieren.
Naja, das A20-Gate ist nichts kompliziertes. Lies dir den Wiki-Artikel (http://lowlevel.brainsware.org/wiki/index.php/A20-Gate) durch und du bist informiert. Der PM ist natürlich ein ganz anderes Kaliber und genau das, womit sich die ganzen Tutorials viele Kapitel lang befassen. Die grundlegenden Sachen findest du in jedem Tutorial und im Wiki erklärt, aber wenn du die Details, die keiner benutzt, auch wissen willst, wird dir nichts übrig bleiben, als dir das Intel-/AMD-Manual vorzunehmen.
@EDIT: Eine Frage habe ich noch. Ich würde gerne zu lerntechnischen Zwecken das Rad neu erfinden und würde gerne ein eigenes Dateisystem (mit Format) erfinden und nicht vorhandene Dateitypen, wie z.B. PDF, unterstützen. Dies ist zwar nicht effektiv und nicht unbedingt intelligent, aber ich will es gerne lernen, wie es ist ALLES selber zu machen. Was denkt ihr darüber?
Halte ich für keine gute Idee. Du wirst zwar am Ende irgendwas haben, das irgendwie funktioniert, aber es wird vermutlich nicht optimal sein. Implementier lieber ein, zwei andere Dateisysteme (FAT und ext2 bieten sich an), damit du die Konzepte lernst, die andere verwenden. Wenn du dann immer noch nicht genug hast, kannst du immer noch dein eigenes FS anfangen, aber eben mit etwas mehr Hintergrundwissen.
-
Halte ich für keine gute Idee. Du wirst zwar am Ende irgendwas haben, das irgendwie funktioniert, aber es wird vermutlich nicht optimal sein. Implementier lieber ein, zwei andere Dateisysteme (FAT und ext2 bieten sich an), damit du die Konzepte lernst, die andere verwenden. Wenn du dann immer noch nicht genug hast, kannst du immer noch dein eigenes FS anfangen, aber eben mit etwas mehr Hintergrundwissen.
Ok. Ich würde dann doch irgendwie mehr zu ext2 als FAT tendieren, aber für ne initrd oder ein VFS reicht es ja, wenn ich selber was mixe oder beispielsweise das von James Molloy nehme, oder?
Das mit dem Hybrid-Kernel werde ich mir eh einmal durch den Kopf gehen lassen müssen.
Eine Frage habe ich schon wieder: Wenn ich keine C++-Klassen benutzen will, wie kann ich beispielsweise Video-Funktionen in C in einer "Klasse", "Schnittstelle" oder einem "Namespace" verpacken? Was gibt es da so für Möglichkeiten? (Dachte mir jetzt ne kleine Map zu machen mit eindeutigen Identifiern und dann so bestimmte Funktionen aufrufen zu können per CALL( VideoDriver, ClearTTYScreen ) (<= Pseudo Code) oder so ähnlich.
-
Ok. Ich würde dann doch irgendwie mehr zu ext2 als FAT tendieren, aber für ne initrd oder ein VFS reicht es ja, wenn ich selber was mixe oder beispielsweise das von James Molloy nehme, oder?
Ja, wenn du nur ein FS implementieren willst, nimm ext2. Das ist zwar etwas aufwendiger, aber dafür hast du am Ende was ordentliches.
Das VFS hat damit nichts zu tun. Das VFS entscheidet mehr oder weniger nur, an welchen FS-Treiber eine Anfrage weitergeleitet wird. Wenn du /mnt/foo öffnest, stellt er also fest, dass das im ext2-Dateisystem, das auf /mnt gemountet ist, liegt und leitet an den ext2-Treiber eine Anfrage weiter, /foo auf dem Dateisystem zu öffnen.
Eine Frage habe ich schon wieder: Wenn ich keine C++-Klassen benutzen will, wie kann ich beispielsweise Video-Funktionen in C in einer "Klasse", "Schnittstelle" oder einem "Namespace" verpacken? Was gibt es da so für Möglichkeiten?
Wenn es dir nur um Namespaces geht: Nimm bei globalen Funktionen für jedes Modul ein Präfix dazu: video_clear_screen. Funktionen und Variablen, die nicht öffentlich sein sollen, werden static.
Wenn du Vererbung brauchst, kanst du structs mit Funktionspointern nehmen.
-
Wie würde dann eine solche Funktions-Pointer-Struct aussehen? (Jetzt mit meinem Beispiel Video::ClearScreen())
(Habe dich bei ICQ geadded. Kannst ja mal annehmen xD)
-
Dein Beispiel hat keine Vererbung drin, also ist es nicht besonders sinnvoll, hier Funktionspointer herzunehmen. Um das erklären zu können, nehme ich einfach mal an, es gibt zwei verschiedene Backends, eins für Textmodus, eins für Grafikmodus.
Wir hätten also global ein:
struct video_drv {
void (*clear_screen)(void);
}
Dann in einer text.c:
static void text_clear_screen(void) {
// Bildschirm löschen halt
}
struct video_drv textmode_drv = {
.clear_screen = text_clear_screen;
};
Und nochmal ganz woanders hast du ein Bildschirmobjekt, das entweder Grafik- oder Textmodus hat (weiß man nicht so genau, deswegen muss die Vererbung das erledigen) und machst dann sowas:
screen.drv->clear_screen();
Sie sahen: Einführung in die objektorientierte Programmierung mit C, Teil 1. Alle Klarheiten beseitigt? ;)
-
Hallo taljeth,
Sie sahen: Einführung in die objektorientierte Programmierung mit C, Teil 1. Alle Klarheiten beseitigt? :wink:
Cool, jetzt fehlt nur noch Mehrfachvererbung und Exception-Handling! :-D
Aber mal im Ernst, dieses Thema könnte man sicher gut in ein Tutorial verpacken um zu zeigen wie man in C einfache Interfaces implementiert hinter dehnen sich verschiedene Implementierungen verstecken können.
Grüße
Erik
-
Sie sahen: Einführung in die objektorientierte Programmierung mit C, Teil 1. Alle Klarheiten beseitigt? :wink:
Cool, jetzt fehlt nur noch Mehrfachvererbung und Exception-Handling! :-D
Den Teil überlasse ich gern dir. Für die Exceptions lässt sich mit setjmp/longjmp doch sicher was basteln und mit ein paar Makros in annehmbare Syntax verpacken. ;)
Aber mal im Ernst, dieses Thema könnte man sicher gut in ein Tutorial verpacken um zu zeigen wie man in C einfache Interfaces implementiert hinter dehnen sich verschiedene Implementierungen verstecken können.
Hm, eigentlich ist das ja Off Topic bei uns. Das ist jetzt nicht irgendwie was, was besonders OS-Dev-spezifisch wäre, sondern es ist halt Programmierung in C. Keine Ahnung, in welchem Zusammenhang ich das unterbringen sollte.
-
Hallo taljeth,
Den Teil überlasse ich gern dir. ....
Hm, währ mal ne Herausforderung, aber eigentlich setze ich dann doch lieber gleich auf C++ und überlas das ganze dem Compiler.
Keine Ahnung, in welchem Zusammenhang ich das unterbringen sollte.
Treiber-Interfaces. Zumindest in einem monolitischen Kernel mit Modulen, wie z.B. Linux, wird sowas sehr oft benötigt. Gerade im Linux-Kernel funktioniert fast alles so, ich frage mich warum dort keiner C++ benutzt, sowas wie Exceptions muss man ja nicht benutzen.
Grüße
Erik
-
Treiber-Interfaces. Zumindest in einem monolitischen Kernel mit Modulen, wie z.B. Linux, wird sowas sehr oft benötigt. Gerade im Linux-Kernel funktioniert fast alles so, ich frage mich warum dort keiner C++ benutzt, sowas wie Exceptions muss man ja nicht benutzen.
http://thread.gmane.org/gmane.comp.version-control.git/57643/focus=57918 ist nicht Antwort genug? ;)
Hm, ja, zu CDI wollte ich ja sowieso noch was schreiben. Beim Erklären, wie CDI funktioniert, wird ja dann sowieso auch implizit deutlich werden, wie man sowas machen kann. Aber für Mehrfachvererbung bräuchte ich erstmal selber ein brauchbares Konzept...
-
Hallo taljeth,
Hm, ja, zu CDI wollte ich ja sowieso noch was schreiben.
Dann hab ich nichts gesagt.
Aber für Mehrfachvererbung bräuchte ich erstmal selber ein brauchbares Konzept...
Das hatte ich auch nicht ernst gemeint.
Ich denke mal es wird für jede Klasse (nicht für jedes instantiierte Objekt) für jede beerbte Eltern-Klasse eine passende vtable erstellt so das der Code zur Laufzeit sich nur die vtable raussuchen muss die zu dem erwarteten Typ, was ja eine Eltern-Klasse des tatsächlich vorhandenen Typs sein muss, passt. Diese vtable muss genau so aufgebaut sein,aber eben nicht den selben Inhalt haben, wie die die zu der entsprechenden Eltern-Klasse direkt gehört. Man bräuchte dann nur noch eine Funktion welche zum aktuellem Klassen-Typ eine vtable raussucht die dem Typ des gewünschten Eltern-Klassen-Typs entspricht. So würde ich zumindest versuchen das Problem zu lösen, das echte C++-Compiler das viel besser/eleganter/effizienter können ist aber sehr wahrscheinlich. Wir sollten das Rad jedenfalls kein zweites mal neu erfinden, signifikant runder bekomm ich das ganz sicher nicht hin.
Grüße
Erik
-
Hallo taljeth,
http://thread.gmane.org/gmane.comp.version-control.git/57643/focus=57918 ist nicht Antwort genug? :wink:
Da streiten Dinosaurier über Probleme von (fetten) Dinosauriers, da halte ich mich lieber raus. :wink:
In meinem OS wird der Micro-Kernel sicher zu guten Teilen direkt in Assembler (nach VHDL meine zweitliebste Programmiersprache) entstehen aber die ganzen umliegenden Schichten, User-Mode-Applikationen welche die Personlity liefern und Treiber darstellen, werden bestimmt C++ sein.
Grüße
Erik
-
Du hast nach Linux gefragt, also gebe ich eine Antwort von Linus. ;)
Aber für Mehrfachvererbung bräuchte ich erstmal selber ein brauchbares Konzept...
Das hatte ich auch nicht ernst gemeint
Ich aber schon. Es gibt nämlich Hardware, die sowohl ein PCI-Gerät als auch eine Netzwerkkarte ist. C++ ist für CDI keine wirkliche Option, weil es OS-unabhängig sein soll, und da ist C nunmal der kleinste gemeinsame Nenner.
Ich denke mal es wird für jede Klasse (nicht für jedes instantiierte Objekt) für jede beerbte Eltern-Klasse eine passende vtable erstellt so das der Code zur Laufzeit sich nur die vtable raussuchen muss die zu dem erwarteten Typ, was ja eine Eltern-Klasse des tatsächlich vorhandenen Typs sein muss, passt.
Das klingt so einfach, aber mir fällt da nichts vernünftiges ein, wie man das machen könnte. Bei Einfachvererbung kann ich einfach festlegen, dass die struct die Vaterklasse als erstes Element enthalten muss, damit ich direkt casten kann. Bei Mehrfachvererbung könnte ich maximal noch anfangen, ein Array von Vaterklassen anzulegen, die ich dann beim Aufrufen durchgehe und die richtige raussuche. Das klingt aber schon etwas umständlicher zu benutzen als einfach ein Zugriff auf ein struct-Element.
-
Hallo,
Ich aber schon. Es gibt nämlich Hardware, die sowohl ein PCI-Gerät als auch eine Netzwerkkarte ist.
Das ist aber noch keine Mehrfachvererbung. Außerdem sind PCI-Devices immer auch irgendwas nützliches so das dieser Zusammenhang nicht zwangläufig durch Vererbung hergestellt werden sollte. Das Device-Struct sollte ein Member "BUS", Pointer auf ein BUS-Struct, haben und hinter diesem kann sich das passende BUS-System verbergen. Die Infos die das BUS-System liefern muss, also die zugewiesenen Hardwareressourcen, sind immer die selben.
und da ist C nunmal der kleinste gemeinsame Nenner.
Das ist natürlich ein Argument. Wenn Kompatibilität ein Designziel ist dann muss man dem eben auch gehorchen.
Bei Mehrfachvererbung könnte ich maximal noch anfangen, ein Array von Vaterklassen anzulegen, die ich dann beim Aufrufen durchgehe und die richtige raussuche.
Ich vermute so ähnlich wird das auch gemacht. Nur würde ich bei allen Klassen die virtuelle Methoden enthalten als ersten Eintrag in der vtable eine Funktion referenzieren die für den aktuellen tatsächlichen Typ (daher hat jedes Objekt eine Typ-ID o.ä.) des Objekts eine passende vtable für den gewünschten Typ, eben eine Elternklasse, zurückgibt nur das die Einträge in dieser vtable auf die abgeleiteten Methoden verweisen. Ob es wirklich so gemacht wird weis ich nicht aber ich würde das so versuchen falls ich nicht noch irgendwelche Stolperfallen übersehen hab.
Grüße
Erik
-
Das ist aber noch keine Mehrfachvererbung.
Was mehr als eine Vaterklasse hat, ist bei mir schon Mehrfachvererbung.
Außerdem sind PCI-Devices immer auch irgendwas nützliches so das dieser Zusammenhang nicht zwangläufig durch Vererbung hergestellt werden sollte. Das Device-Struct sollte ein Member "BUS", Pointer auf ein BUS-Struct, haben und hinter diesem kann sich das passende BUS-System verbergen.
Ja, aus der is-a-Beziehung ein has-a zu machen, ist auch das, was ich gemacht habe. Allerdings bin ich nicht auf die Idee gekommen, es als Bus zu verallgemeinern. Wenn man sich mal in eine Richtung verrannt hat, übersieht man aber oft das Offensichtliche - du hast vollkommen recht, als Bus könnte man das ohne weiteres jedem Gerät geben und PCI ist dann eben davon abgeleitet. Danke. :)
-
Hallo,
Was mehr als eine Vaterklasse hat, ist bei mir schon Mehrfachvererbung.
Das ist nicht ganz richtig. Wenn C von B abgeleitet ist und B von A dann ist das nur mehrfache Einfachvererbung, wenn C direkt von A und B abgeleitet ist dann ist das Mehrfachvererbung.
siehe http://de.wikipedia.org/wiki/Vererbung_%28objektorientierte_Programmierung%29#Mehrfachvererbung
Das A und B selber wieder von D abgeleitet sein können ist dann das Diamond-Problem.
siehe http://de.wikipedia.org/wiki/Diamond-Problem
als Bus könnte man das ohne weiteres jedem Gerät geben
Damit würde ein Gerät auch seine physische Position in der Baum-Architektur kennen was z.B. fürs Power-Management wichtig ist. Monitor A hängt an Graphikkarte B und die hängt auf dem PCI-Bus-Segment C welches hinter PCI-2-PCI-Bridge D usw. Wenn Du die Graphikkarte in Powerdown schicken möchtest musst Du wissen das davon zwangsläufig der Monitor betroffen ist und zusätzlich kannst Du die PCI-2-PCI-Bridge bzw. den einen Downstream-Port abschalten wenn auf dem Bus-Segment nichts anderes mit drauf ist.
.... und PCI ist dann eben davon abgeleitet
Denke auch an PCI-Express, da gibt es schon ein paar Dinge die ein klein wenig anders sind. Der Config-Address-Space ist z.B. von 256 Bytes auf 4096 Bytes gewachsen. Bei PCI-Express lassen sich auch Hardware-Fehler besser zuordnen, falls Du mal Machine-Check-Exceptions unterstützen möchtest ist das von großem Nutzen.
Grüße
Erik
-
Was mehr als eine Vaterklasse hat, ist bei mir schon Mehrfachvererbung.
Das ist nicht ganz richtig. Wenn C von B abgeleitet ist und B von A dann ist das nur mehrfache Einfachvererbung, wenn C direkt von A und B abgeleitet ist dann ist das Mehrfachvererbung.
Schon klar, ich bin auch nicht völlig ahnunglos. ;)
Ich hätte mehr als eine direkte Vaterklasse sagen sollen. Aber das ist bei Netzwerkkarte und PCI ja eindeutig der Fall, denn nicht alle Netzwerkkarten sind PCI und schon gar nicht alle PCI-Geräte sind Netzwerkkarten.
Deine übrigen Anmerkungen sind auch sicher richtig, spielen aber momentan nicht wirklich eine Rolle. Solange sich die ganz grundlegende Struktur dadurch nicht ändert, kann man später ja immer noch ohne weiteres neue Sachen hinzufügen.
-
Hallo taljeth,
Schon klar, ich bin auch nicht völlig ahnunglos. :wink:
Entschuldige Bitte, ich wollte auf gar keinen Fall als Oberlehrer rüberkommen.
Die übrigen Anmerkungen waren nur so um mal über den Tellerrand zu sehen. In meiner Plattform muss ich wohl auf jeden Fall PCI-Express verwenden, daher habe ich mich damit recht intensiv beschäftigt, aber z.B. das Fehlermanagement werde ich auch nur so weit wie unbedingt nötig unterstützen.
Grüße
Erik
-
Wenn du dich sowieso damit beschäftigen musst, kannst du ja vielleicht bei Gelegenheit einen Wikiartikel dazu schreiben? PCI Express dürfte jedenfalls zu den Themen gehören, denen sich bisher kaum jemand hier gewidmet hat, die aber trotzdem eine gewisse Relevanz haben.
Und falls du dich mit CDI anfreunden kannst, wäre ich natürlich auch nicht abgeneigt, entsprechenden Code aufzunehmen. ;)
-
Hallo,
... kannst du ja vielleicht bei Gelegenheit einen Wikiartikel dazu schreiben?
Kannst Du mal schreiben was Du in so einem Artikel alles drin haben möchtest.
falls du dich mit CDI anfreunden kannst, ...
Das kann ich momentan noch nicht sagen, aber wenn ja dann bekommst Du gerne etwas Code ab. :wink:
Grüße
Erik
-
Um sagen zu können, was ich in dem Artikel haben möchte, müsste ich mich mehr damit auskennen. ;) Ich dachte einfach an die Grundlagen, was anders ist als mit "normalem" PCI und wie man es benutzen kann. Und ein paar Links zu den entsprechenden Dokumenten, falls wir das noch nicht haben.
-
Der ConfigSpace wurde erweitert und es kommen neue Capabilities (gibt ja da diese schöne Linked List) dazu. Ansonsten ändert sich afaik von Softwareseite erstmal nicht wirklich was.
-
Hallo,
Ich dachte einfach an die Grundlagen, was anders ist als mit "normalem" PCI und wie man es benutzen kann.
Dazu gibt es eigentlich nicht viel zu schreiben, wenn das PC-BIOS fertig ist fühlt sich PCI-Express (ebenso wie AGP und Hypertransport) für die SW genau so an wie PCI. Solange Du nicht vorhast die Geräte-Enumeration und -Konfiguration selbst durch zu führen (mal ehrlich wer hier macht das schon) brauchst Du Dich nicht mit der Link-Konfiguration, den erweiterten Bridges und anderen Dingen (die außer den BIOS-Entwicklern niemand interessieren) rumzuschlagen.
Ansonsten sind die Artikel in der Wikipedia gar nicht mal schlecht.
Grüße
Erik
-
Also ich habe mal hard-coded Interfaces eingebaut à la:
#define INTERFACE typedef struct
INTERFACE _IConsole
{
VOID ( *ClearScreen )( VOID );
UINT ( *PutS )( /* ... */ );
/* ... */
} IConsole;
// I-wo im Code
VOID InitIConsole( IConsole *pIConsole )
{
( *pIConsole ).ClearScreen = RealClearScreenFunction; // =)
/* ... */
// Ich habe für Trieiber besondere Funktionen __init() und __kill definiert.
}
/* ... */
InitIConsole( &AnyNewIConsoleObject );
Was Vererbung angeht geht das hard-coded so:
INTERFACE _IAbstractDriver
{
BOOL ( *__init )();
BOOL ( *__kill ) ();
/* ... */
} IAbstractDriver;
/* ... */
INTERFACE _IMyDriver
{
IAbstractDriver Device; // habe nen #define DRIVER IAbstractDriver Device i-wo
} IMyDriver;
Ist zwar etwas Anfänger-Style, aber es tut was es soll. Ich überlege imo in der IAbstractDriver dann Daten über die Treiber, wie z.B. Namen und so, zu speichern. Dann kann man die Daten in verketteten Listen speichern.
Mir ist dieses modulare und dynamische Design sehr wichtig, da dann die Wartung relativ einfach fallen könnte.
Wie findet ihr meinen ersten Ansatz? Was lässt sich noch ausbauen?
-
Findest du nicht, dass dieses INTERFACE den Code nur schwerer lesbar macht, weil du nicht mehr direkt hinschreibst, was du eigentlich meinst?
Ansonsten, du scheinst im Moment jedem Objekt einzeln die ganzen Funktionspointer zuzuweisen. Es wäre wahrscheinlich sinnvoller, nur eine Struktur mit den ganzen Pointern zu definieren und im Objekt nur noch auf diese Struktur zu zeigen. Man kann's aber natürlich auch so machen wie du.
-
Momentan ist es so, dass ich beispielsweise IConsole nur einmal habe (Stichwort Singleton) und das so mache. Wenn ich nen neues Interface Objekt erstelle muss ich eigentlich nur die InitI<Name>( I<Name> *Pointer ) aufrufen.
Ich persönlich finde INTERFACE besser, aber du hast schon Recht, wenn andere es sehen...nja. Deinen zweiten Punkt mit den redundaten Pointern werde ich beachten! Danke sehr!
Noch irgendwelche Hinweise?