ERLEDIGT
NEIN
NEIN
ANTWORTEN
12
12
ZUGRIFFE
1648
1648
EMPFEHLEN
-
29.01.10 14:35 #1canfänger Tutorials.de Gastzugang
Hi!
Ich würde gern wissen ob man C-strukturen verschachteln kann um eine Art Vererbung wie in C++ etc. zu simulieren,. Der Code unten produziert bei mir keine Fehler, doch soweit mir das bekannt ist optimieren die Compiler die interna von Structs (Alignment etc.) - kann ich dennoch guten Gewissens so arbeiten?Code C:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
typedef struct { unsigned length; unsigned width; } quad_t; typedef struct { quad_t base; unsigned height; } cube_t; static int print_quad_values(FILE *stream, quad_t *quad) { return fprintf( stream, "Length: %u\nWidth: %u\n", quad->length, quad->width ); } /* .. */ int main(void) { /* .. */ cube_t *cube = (cube_t*) malloc(sizeof(cube_t)); /* .. */ print_quad_values(stderr, (quad_t*) cube); /* .. */ free(cube); /* .. */ return 0; }
Danke im Vorraus
Peter
-
29.01.10 14:55 #2jsendrow Tutorials.de Gastzugang
Das hat mit Vererbung nix zu tuen. Der Fachbegriff für das, was Du da machst ist Composition ( http://en.wikipedia.org/wiki/Object_composition )
Vererbung basiert auf ein IS-Beziehung (a car IS a moving object), Komposition auf einer HAS-Beziehung (a car HAS a engine)
-
29.01.10 15:01 #3
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Man kann. Du könntest dir z.B. mal die GLib und insbesondere das Typsystem und GObject (http://library.gnome.org/devel/gobje...r-gobject.html) anschauen.
GrußIf at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
29.01.10 15:06 #4
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Die OOP Geschichte von der du sprichst, ist doch nichts weiter als ein philosophisches Konzept. Die Frage ist letztendlich wie man das im Rechner umsetzen kann.
Natürlich hat canfänger hier eine Art Vererbung erreicht denn (abstrakt gesehen) ist eine cube_t eben immer auch ein quad_t.
Auf der Objektcode-Ebene wurde hier lediglich ein Typ erstellt der mit einen anderen benutzerdefinierten Typ enthält. Etwas anderes passiert bei C++ auch nicht.
GrußGeändert von deepthroat (29.01.10 um 15:20 Uhr)
If at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
„Gib einem Menschen einen Fisch, und er wird für einen Tag satt. Lehre ihn Fischen, und er wird ein Leben lang satt.“
“For every complex problem, there is an answer that is short, simple and wrong.”
“Pessimism is safe, but optimism is a lot faster!”
Aktuelles Coding Quiz: #17 - Wörter kreuz und quer
-
29.01.10 17:15 #6canfänger Tutorials.de Gastzugang
Danke für die Antworten!
Wie deepthroat schon vermutet hat, es ist mir ziemlich egal ob mein Beispiel oben nun wirklich Vererbung oder wasweisich ist. Mich interessierte nur, ob es eine sichere Operation ist, einen Pointer auf ein cube_t in einen Pointer auf ein quad_t zu casten (Zeile 24).
Ich habe schon gesehen dass man einfach die Felder im basis-Typ zu beginn des erweiterten Types wiederholt, will aber das Tippen und eventuelle Aktualisieren an mehreren Stellen umgehen.
Vielen Dank nochmal!
Peter
-
29.01.10 17:40 #7
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Beantwortet ist die Frage ja eigentlich schon, aber es ist sogar logisch
Für ein struct S gilt immer:
D.h. die Adresse wo die Struktur im Speicher liegt ist immer gleich der Adresse des ersten Members. Also es gibt höchstens Padding aufgrund von Alignment zwischen den Komponenten einer Struktur, aber nie am Anfang.Code :1
&S == &S.firstMember
GrußIf at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
Du kannst in einem struct sogar Zeiger auf Funktionen speichern. Wenn du die richtig setzt, kannst du sie aufrufen, als wären es (Klassen-) Methoden.
Geändert von Vereth (30.01.10 um 08:09 Uhr)
Vielen Dank für die Nutzung des Bewerten- und Danke-Buttons
Wenn man sieht, dass man einen anderen glücklich gemacht hat, ist die Welt um zwei glückliche Menschen reicher.
-
01.02.10 12:06 #9canfänger Tutorials.de Gastzugang
Ja, aber...
ist das dann nicht ähnlich den virtuellen Funktionen in C++? Ok, hier habe ich keine vptr, bzw. keine komplette Tabelle, aber ein Funktionsaufruf über Zeiger ist doch resourcenlastiger als ein handgeschriebener aufruf einer Funktion - vorrausgesetzt der Compiler "inlined" die Anweisungen nicht..?
Gruß
Peter
-
Mein Post war eher scherzhaft gemeint, aber das Thema scheint dich derartig zu interessieren, dass ich dir eine ausführlichere Darstellung gönne.
Der Bezeichner einer Funktion ist immer ein Zeiger auf diese Funktion. Der Zeiger verweist dabei allerdings nicht auf Daten, sondern auf ausführbaren Programmcode. Deswegen kann man auch Variablen deklarieren, denen eine Funktion (genauer den Zeiger darauf) zugewiesen werden kann. Bei der Deklaration muss diese Funktionszeiger-Variable dieselbe Signatur haben, wie die Funktion, die dieser zugewiesen werden soll, d.h. der Rückgabewert und die Parameter müssen dieselben Datentypen haben. Wenn dieser Variablen eine gültige Funktion zugewiesen wurde, dann kann diese Funktion über die Variable genauso aufgerufen werden, als wenn diese die Funktion selber wäre.
Beim Aufrufen einer Funktion werden immer als erstes die Parameter auf den Stack gepusht; diese Arbeit erledigt stets das aufrufende Programm. Das gilt auch für das Zurückliefern des Funktionsaufrufes, der durch das aufrufende Programm vom Stack gepopt wird. Der Zeiger verseist im wesentlichen auf die Informationen, wie diese Funktion aufzurufen ist, ob über ein zu ladendes Modul oder, bei selbst geschriebenen Funktionen, direkt in den Code des laufenden Programms. Deswegen ist der Ablauf beim Aufruf einer Funktion immer der gleiche, egal, ob du die Funktion über einen Funktionszeiger oder über den 'Original'-Namen aufrufst; eine zusätzliche Dereferenzierung findet nicht statt. Es existiert also weder über zusätzlichen Speicherplatz noch über eine zusätzliche Dereferenzierung eine Mehrbelastung der Systemressourcen. Die Deklaration eines Funktionszeigers und die Zuweisung einer gültigen Funktion an diese Zeigervariable ist der einzige Mehrbedarf, der dabei anfällt.
Meistens wird dieses Feature nicht benötigt. Allerdings gibt es manchmal Problemstellungen, in denen die Verwendung von Funktionszeigern sinnvoll ist. Ein klassisches Beispiel ist die Übergabe einer Vergleichs-Funktion an eine Sortierroutine, z.B. qsort. Eine gute, allerdings englische, Beschreibung dieses Themas findest du bei http://www.newty.de/.Vielen Dank für die Nutzung des Bewerten- und Danke-Buttons
Wenn man sieht, dass man einen anderen glücklich gemacht hat, ist die Welt um zwei glückliche Menschen reicher.
-
Das stimmt nicht uneingeschränkt. Es gibt eine Vielzahl von Aufrufkonventionen. Bei einigen muss der aufrufende Programmteil den Stack aufräumen, bei anderen erledigt das das aufgerufene Unterprogramm. Auch müssen Parameter nicht immer über den Stack übergeben werden, man kann dazu z.B. auch die CPU-Register verwenden. Die meisten Compiler für die x86-Architektur übergeben den Rückgabewert einer Funktion beispielsweise über das EAX-Register.
Nein. Wie die Funktion aufzurufen ist, bestimmt schon der Zeigertyp. Der Zeiger verweist lediglich auf den Einsprungspunkt der Funktion.
Doch, bei Funktionszeigern findet im Allgemeinen eine zusätzliche Dereferenzierung statt. Eine normaler Funktionsaufruf (ohne Funktionszeiger) entspricht einem Sprung an eine feste Adresse im Speicherbereich des Programms. Diese ermittelt der Linker zur Kompilierzeit und trägt sie an den entsprechenden Stellen ein. Dagegen steht die Adresse, auf die ein Funktionszeiger verweist, erst zur Laufzeit fest. Das Programm muss also zuerst diese Adresse auslesen und kann erst dann den Sprung ausführen.
Grüße,
Matthias„Gib einem Menschen einen Fisch, und er wird für einen Tag satt. Lehre ihn Fischen, und er wird ein Leben lang satt.“
“For every complex problem, there is an answer that is short, simple and wrong.”
“Pessimism is safe, but optimism is a lot faster!”
Aktuelles Coding Quiz: #17 - Wörter kreuz und quer
-
Wer den Stack aufräumt, ist letzlich egal; es ist eine Arbeit, die in jedem Fall gemacht werden muss. Allerdings denke ich, dass die aufgerufene Funktion immer einen gewissen Teil selber machen muss, da nur sie weiß, wie viele auto-Variablen sie angelegt hat.
Der Zeiger verweist lediglich auf den Einsprungspunkt der Funktion, das ist richtig. Aber bei Funktionen, die nicht statisch gebunden wurden, weil sie z.B. in einer DLL sind, verweist der Funktionszeiger auf einen Stub, der dafür sorgt, dass diese DLL auch geladen und ausgeführt wird. Aber das ist für die eigentliche Thematik irrelevant.
Ich sehe ein, dass eine zusätzliche Dereferenzierung notwendig ist. Aber darüber hinaus entsteht wohl kein zusätzlicher Aufwand. Zudem ist die Dereferenzierung eine schnelle Operation, die auf die Laufzeit eines Programms kaum Auswirkung hat.Vielen Dank für die Nutzung des Bewerten- und Danke-Buttons
Wenn man sieht, dass man einen anderen glücklich gemacht hat, ist die Welt um zwei glückliche Menschen reicher.
-
Klar. Ich wollte nur aufzeigen, dass es unterschiedliche Aufrufkonventionen gibt.
Auch das ist wieder nicht die ganze Wahrheit. Du beschreibst hier das verzögerte Laden von DLLs. Das ist aber nicht die einzige Möglichkeit, DLLs zu verwenden. Im Regelfall werden DLLs schon beim Programmstart geladen und die Adressen der Einstiegspunkte der DLL-Funktionen in die Import-Adresstabelle (IAT) eingetragen. Beim Aufruf einer DLL-Funktion wird dann an die entsprechende Stelle in der IAT gesprungen. Dort ist ein Sprungbefehl an die vom Lader eingetragene Adresse enthalten, welcher als nächstes ausgeführt wird. Man kann die DLL außerdem noch „per Hand“ laden (LoadLibrary) und sich die Einstiegspunkte holen (GetProcAddress) – beim „automatischen“ verzögerten Laden geschieht das genauso.
Aber wie du schon sagtest:

Grüße,
Matthias„Gib einem Menschen einen Fisch, und er wird für einen Tag satt. Lehre ihn Fischen, und er wird ein Leben lang satt.“
“For every complex problem, there is an answer that is short, simple and wrong.”
“Pessimism is safe, but optimism is a lot faster!”
Aktuelles Coding Quiz: #17 - Wörter kreuz und quer
Ähnliche Themen
-
Liste für 2 Structs
Von Need_Name im Forum C/C++Antworten: 8Letzter Beitrag: 04.01.10, 14:49 -
C++ structs lesen
Von Orthak im Forum C/C++Antworten: 7Letzter Beitrag: 13.01.09, 21:21 -
sort vector von structs
Von Thomasio im Forum C/C++Antworten: 9Letzter Beitrag: 17.03.08, 15:38 -
Protokollsachen: Structs aus C++ übernehmen?
Von BeaTBoxX im Forum .NET Application und Service DesignAntworten: 3Letzter Beitrag: 15.12.06, 13:39 -
[C] Warnung bei structs
Von rookie im Forum C/C++Antworten: 3Letzter Beitrag: 10.02.03, 12:55





Zitieren

Login






