Hallo C-Spezialisten, ich muß von C++ nach C absteigen, mit Grausen... kann ich in C struct eine "Memberfunktion" definieren? Beispiel, bei dem der Metrowerks meckert: typedef enum _tTaskState_ { TS_IDLE = 0, TS_BUSY = 1 } tTaskState; typedef enum _tTaskError_ { TE_NONE = 0, TE_ERROR = 1 } tTaskError; typedef struct _tTask_ { tTaskState m_eState; tTaskError m_eError; void Initialize(void); } tTask; tTask Task1; tTask Task2; in main wollte ich dann das C++ like machen: ... Task1.Initialize(); ... Geht das in Hardcore C nicht? Was muß ich ändern um solche Ausdrücke zu erhalten: Task1.Initialize(); Vielen Dank für eure Hilfe! Manfred
In C benutzt du keine Memberfunktionen :-) Immer schön Daten und Code trennen, z.B. so: typedef struct _tTask_ { tTaskState m_eState; tTaskError m_eError; } tTask; void Initialize_tTask(tTask* pTask); // evntl. mit Rückgabewert? Alles andere ist IMHO kein C sondern irgendein Mischmasch...
Hi man kann schon eine Art "Member-Funktionen" für Strukturen verwenden. Nur muss man dann eben alles was der C++ Compiler macht von Hand machen. Nicht umsonst waren die ersten verfügbaren C++ Compiler reine Textparser die aus dem C++ Sourcecode C Code erzeugt haben welcher dann von einem normalen C-Compiler übersetzt wurden konnte. Es braucht halt sehr viel Disziplin wenn man this-Zeiger, vtable, Kon- und Destruktoraufrufe usw. händisch verwalten muss. C++ ist eine Programmiersprache für Männer. C ist eine für Helden :-) Matthias
Etwas ähnliches kann man in C so realisieren:
1 | typedef struct test_s { |
2 | int a; |
3 | int b; |
4 | |
5 | void (*Initialize)(void); |
6 | } test_t; |
7 | |
8 | void
|
9 | init(void) |
10 | {
|
11 | printf("Init!\n"); |
12 | }
|
13 | |
14 | test_t test1 = {0, 0, &init}; |
15 | |
16 | int
|
17 | main(void) |
18 | {
|
19 | test1.Initialize(); |
20 | |
21 | return 0; |
22 | }
|
Ob das Deinen Vorstellungen nahe kommt, kann ich nicht sagen, da ich von C++ so gut wie überhaupt keine Ahnung habe...
Hi @Patrick Das ist nicht das was Manfred erreichen möchte. Es fehlt der init-Funktion nämlich der Bezug zur Instanz der Struktur von der aus sie aufgerufen wurde. Wenn dann müßte man das etwa so realisieren:
1 | typedef struct test_s { |
2 | int a; |
3 | int b; |
4 | |
5 | void (*Initialize)(void *); |
6 | void (*Foo)(void *); |
7 | void (*Bar)(void *); |
8 | } test_t; |
9 | |
10 | void init(void * p) |
11 | {
|
12 | test_t * this = p; |
13 | |
14 | this->a = 1; |
15 | this->b = 4; |
16 | }
|
17 | |
18 | void foo(void * p) |
19 | {
|
20 | test_t * this = p; |
21 | //Do something
|
22 | }
|
23 | |
24 | void bar(void * p) |
25 | {
|
26 | test_t * this = p; |
27 | //Do something else
|
28 | }
|
29 | |
30 | test_t test1 = {0, 0, init, foo, bar}; |
31 | |
32 | int main(void) |
33 | {
|
34 | test1.Initialize(&test1); |
35 | test1.Foo(&test1); |
36 | test1.Bar(&test1); |
37 | |
38 | return 0; |
39 | }
|
Nichts anderes macht ein C++-Compiler. Jede Methode hat einen zusätzlichen, versteckten Parameter. Und das ist eben der this-Zeiger. Matthias
Aha! Danke für die gute Erläuterung! Ich wäre schon beinahe selber drauf gekommen, weil ich eigentlich a und b in der init-Funktion modifizieren wollte. War mir da aber nicht sicher und habs gelassen :-)
Könntest Du mir vielleicht noch erklären, wie sich die Sache dann mit Konstruktoren und Destruktoren verhält? Ich vermute ja die Verwendung von malloc und free...
Hi Konstruktoren und Destruktoren haben (erstmal) nichts mit malloc und free (die man in C++ eh nicht benutzt -> new, delete) zu tun. Ein Konstruktor wird beim Erzeugen (ob jetzt per new, als globales Objekt oder auf dem Stack spielt dabei keine Rolle) eines Objekts aufgerufen und ein Destruktor beim Zerstören eines Objekts. Das wars dann auch schon (insofern keine Vererbung hinzukommt). Matthias
Und wie würde man einen solchen Konstruktor/Destruktor in C realisieren? Es geht mir lediglich um das Verständis...
Hi manuell für jede Instanz einer Struktur einmal aufrufen. Konstruktor unmittelbar nach der Erzeugung der Struktur, Destruktor unmittelbar vor deren Zerstörung. Ein Konstruktor ist nichts anderes (zumindest nicht viel) als eine Member-Methode (so wie oben z.B. Initialize) bei der der C++ Compiler dafür sorgt das sie zur richtigen Zeit aufgerufen wird. Matthias
"Konstruktor unmittelbar nach der Erzeugung der Struktur" Oder der Konstruktor belegt selber den Speicherplatz der Struktur.
Hi, was mache ich denn wenn ich das struct nicht als Reference also auf dem Stack habe. In meinem Fall habe ich lediglich einen Zeiger auf das Struct. struct a_ThreeAddressCode { IMCodeType mOperation; // type of operation IMCode mRegister1; // goal register or label IMCode mRegister2; // first operant IMCode mRegister3; // second operant ThreeAddressCode* mNext; char* (*convertOperation) (void *); }; ich will dann über ne liste iterieren und halt tac->convertOperation(tac); aufrufen. convertOperation wandelt lediglich ein enum in einen char* um.
Aber ausser es muss schlussendlich doch noch ne Art Polymorphismus eingebaut werden wollt ihr ja nicht im Ernst solchen C Code schreiben, oder ?
Im Moment mache ich es so: void writeProgramCode() { ThreeAddressCode root = { tac_root->mOperation, tac_root->mRegister1, tac_root->mRegister2, tac_root->mRegister3, tac_root->mNext, convertOperation }; ThreeAddressCode* temp = &root; while (temp){ fprintf(stdout, "%s\n", root.convertOperation(temp)); temp = root->mNext; } } Die Lösung ist aber nicht grad elegant, wenn ich dahingegen: while (temp){ fprintf(stdout, "%s\n", (*(temp->convertOperation))(temp)); temp = root->mNext; } nehme, dann iteriert er mit nur über das erste Element, und dann ist Schluss. BTW. Kennt sich jemand mit Registerallokation aus? Ich brauche einen Algorithmus, der dies für einen RISC Processor mit 32 Register, wobei R31 ein Zeiger auf den Hauptspeicher ist, durchführt. MfG Manfred
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.