mikrocontroller.net

Forum: PC-Programmierung C-Frage


Autor: Manfred Keindel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sebastian Brückner (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Etwas ähnliches kann man in C so realisieren:
typedef struct test_s {
  int a;
  int b;
  
  void (*Initialize)(void);  
} test_t;

void
init(void)
{
  printf("Init!\n");
}

test_t test1 = {0, 0, &init};

int
main(void)
{
  test1.Initialize();

  return 0;
}

Ob das Deinen Vorstellungen nahe kommt, kann ich nicht sagen, da ich
von C++ so gut wie überhaupt keine Ahnung habe...

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
typedef struct test_s {
  int a;
  int b;
  
  void (*Initialize)(void *);  
  void (*Foo)(void *);
  void (*Bar)(void *);
} test_t;

void init(void * p)
{
  test_t * this = p;

  this->a = 1;
  this->b = 4;
}

void foo(void * p)
{
  test_t * this = p;
  //Do something
}

void bar(void * p)
{
  test_t * this = p;
  //Do something else
}

test_t test1 = {0, 0, init, foo, bar};

int main(void)
{
  test1.Initialize(&test1);
  test1.Foo(&test1);
  test1.Bar(&test1);

  return 0;
}


Nichts anderes macht ein C++-Compiler. Jede Methode hat einen
zusätzlichen, versteckten Parameter. Und das ist eben der this-Zeiger.

Matthias

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

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

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, danke sehr.

Autor: Tobi H. (tobi-) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Konstruktor unmittelbar nach der Erzeugung der Struktur"

Oder der Konstruktor belegt selber den Speicherplatz der Struktur.

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

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

Matthias

Autor: Manfred Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probier mal die Syntax

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

Autor: Bartli (Gast)
Datum:

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

Autor: Manfred Paul (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.