C-Frage

Gast #295842
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
Persönliche Seite #295844
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
Persönliche Seite #295845
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...
Persönliche Seite #295846
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
Persönliche Seite #295849
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
Persönliche Seite #295851
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
Gast #295855
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.
Gast #295858
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren