Forum: PC-Programmierung C-Frage


von Manfred Keindel (Gast)


Lesenswert?

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

von Sebastian Brückner (Gast)


Lesenswert?

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...

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

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...

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

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 :-)

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

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...

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Und wie würde man einen solchen Konstruktor/Destruktor in C
realisieren?
Es geht mir lediglich um das Verständis...

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

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

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Ok, danke sehr.

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

"Konstruktor unmittelbar nach der Erzeugung der Struktur"

Oder der Konstruktor belegt selber den Speicherplatz der Struktur.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

wie meinst du das? Da komm ich jetzt nicht mehr mit.

Matthias

von Manfred Paul (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

Probier mal die Syntax

   (*(tac->convertOperation))(tac)

von Bartli (Gast)


Lesenswert?

Aber ausser es muss schlussendlich doch noch ne Art Polymorphismus
eingebaut werden wollt ihr ja nicht im Ernst solchen C Code schreiben,
oder ?

von Manfred Paul (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.