Forum: Mikrocontroller und Digitale Elektronik C Frage zu Funktionen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Jens (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi,

wie muss ich einen Datentypen ausprägen wenn ich über das Objekt eine 
Funktion aufrufen möchte?

Beispiel:

MeinDatentyp_t Lampe;

ich möchte dann im code beispielsweise schreiben können:

  Lampe.an();
  Lampe.aus();
  Lampe.init();

oder

  Lampe.setzeWert(255);

oder oder oder

das würde ich ja über einen typedef struct machen:

   Lampe.wert=255;


Aber wie bekomme ich die Funktionen ins spiel an der stelle?

Danke

Gruß
JJ

von Curby23523 N. (nils_h494)


Bewertung
0 lesenswert
nicht lesenswert
C ist ein C++! Eher setzeWert(&Lampe, 255);

: Bearbeitet durch User
von npn (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Curby23523 N. schrieb:
> C ist ein C++!

Was willst du damit sagen?

von Mike R. (thesealion)


Bewertung
1 lesenswert
nicht lesenswert
Lampe.an() muss halt ein Pointer auf eine Funktion sein.

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
npn schrieb:
> Was willst du damit sagen?

Dass bei ihm die Taste 'k' klemmt.

: Bearbeitet durch Moderator
von Waldfee (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Ich glaube so müsste es gehen:

struct
{
   void (*An)(void);
   void (*Aus)(void);
}Lampe;

void main (void)
{
  Lampe.An = An();   // Eigendliche An Funktion dem Struct zuweisen
  Lampe.Aus = Aus(); // Selbe wie aus

  while(1)
  {
   Lampe.An();
   Lampe.Aus();
  }


}

von Stefan ⛄ F. (stefanus)


Bewertung
-1 lesenswert
nicht lesenswert
Du möchtest Methoden von Strukturen aufrufen. Das gibt es nicht.
Nur Objekte haben Methoden.

von Waldfee (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Waldfee schrieb:
> Ich glaube so müsste es gehen:
>
> struct
> {
>    void (*An)(void);
>    void (*Aus)(void);
> }Lampe;
>
> void main (void)
> {
>   Lampe.An = An();   // Eigendliche An Funktion dem Struct zuweisen
>   Lampe.Aus = Aus(); // Selbe wie aus
>
>   while(1)
>   {
>    Lampe.An();
>    Lampe.Aus();
>   }
>
> }

Sorry Fehler entdeckt...

 void main (void)
 {
   Lampe.An = An;   // Eigendliche An Funktion dem Struct zuweisen
   Lampe.Aus = Aus; // Selbe wie aus

   while(1)
   {
    Lampe.An();
    Lampe.Aus();
   }

 }

void An(void)

void Aus(void)

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
2 lesenswert
nicht lesenswert
Jens schrieb:
> wie muss ich einen Datentypen ausprägen wenn ich über das Objekt eine
> Funktion aufrufen möchte?

Es gibt keine Objekte in C. Hier gibt es lediglich Datenstrukturen, wo 
man mittels Pointer to Functions etwas objektähnliches 
zusammenschustern kann.

Nach Deiner Frage zu urteilen ginge so ein C-Hack weit über Deine 
momentanen Fähigkeiten hinaus.

Beantworte erstmal die Frage: C oder C++ ?

Wenn Du Objekte meinst, meinst Du wahrscheinlich C++. Ich rate Dir die 
Lektüre eines guten C++-Buchs, um solche elementare Dinge wie Objekte 
und der darauf anzuwendenden Funktionen (Methoden) zu lernen.

Ein Forum ersetzt nicht das Lernen.

von CK (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Man kann es Objektorientierung in C nachbauen, es geht ist aber nicht 
sehr schon.

Man erstellt eine Struktur mit allen Objektvariablen und 
Funktionspointer für die Methoden
struct MyClass {

int (*myMethod)( void* o , int myParam1);
};


Eine Funktion die das New repräsentiert:

MyClass* MyClass_new(); // für dynamisch mit malloc

oder

MyClass myObjekt;
void MyClass_init(&myObjekt); // static ohne malloc


und kann dann die Methode ober das Objekt aufrufen

int ret = myObjekt.myMethod(&myObjekt, 123);

Leider muss man immer den Kontext, also das Objekt, mit als Parameter 
angeben.

Hier ist ein Beispiel wie man sowas Anwendet:
https://github.com/christiankarsch/RP6-I2C-Demo/blob/master/src/lib/linux/i2c/linux_i2c.h

von A. S. (achs)


Bewertung
1 lesenswert
nicht lesenswert
Das Problem: C hat keinen impliziten Self-Pointer.

Dadurch brauchst Du entweder für jede Variable (Instanz) eine eigene 
Funktion An(). Oder musst einen Pointer auf sich selbst übergeben 
(Self-Pointer).

Dadurch sind einzelne Funktionen (Lampe_an(&lampe1)) meist genauso gut 
(oder schlecht;)

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Jens schrieb:
> ich möchte dann im code beispielsweise schreiben können:
>
>   Lampe.an();
>   Lampe.aus();
>   Lampe.init();

Ersetze einfach den '.' durch '_':
Lampe_an();
Lampe_aus();
Lampe_init();

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
so geht's doch prima (wenn man das unbedingt haben will):
#include <stdio.h>

void an(void)
{
    printf("an\n");
}

void aus(void)
{
    printf("aus\n");
}

struct lampe
{
    void (*an)(void);
    void (*aus)(void);
} lampe =
{
    &an,
    &aus
};

int main(int argc, char *argv[])
{
    lampe.an();
    lampe.aus();
}

Nach einem this-Pointer hat bislang keiner gefragt.

von CK (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Markus F. schrieb:
> Nach einem this-Pointer hat bislang keiner gefragt.

Erst wenn es zwei Lampen werden ^^

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
CK schrieb:
> Markus F. schrieb:
>> Nach einem this-Pointer hat bislang keiner gefragt.
>
> Erst wenn es zwei Lampen werden ^^

braucht man immer noch keinen this-pointer:
...
struct lampe
{
    void (*an)(void);
    void (*aus)(void);
} lampe[] =
{
    {
        &an1,
        &aus1
    },
    {
        &an2,
        &aus2
    }
};

int main(int argc, char *argv[])
{
    lampe[0].an();
    lampe[1].aus();
}

von A. S. (achs)


Bewertung
1 lesenswert
nicht lesenswert
Markus F. schrieb:
> braucht man immer noch keinen this-pointer:

Nein, das besagt das "entweder oder" in

Achim S. schrieb:
> Dadurch brauchst Du entweder für jede Variable (Instanz) eine eigene
> Funktion An(). Oder musst einen Pointer auf sich selbst übergeben
> (Self-Pointer).

von PittyJ (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dann nimm doch einfach C++.
Meist reicht es, im Makefile den gcc durch g++ zu ersetzen.

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
BTW: für echte HW, z.B physikalische Uarts des uC, nutze ich das 
exsessiv, also z.b. uart1.put(c);

Der Bildprozess kopiert uart2.c ... uart5.c automatisch,  entsprechende 
Header enthalten die spezifischen Register etc. Der Code wird dadurch 
sauschnell, straight und nicht viel größer als ein generischer.

von Unglaublich (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Achim S. schrieb:
> uart1.put(c);

und was ist da jetzt soviel toller als zu schreiben writeUart(uart1, c);

Nix!

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Unglaublich schrieb:

> und was ist da jetzt soviel toller als zu schreiben writeUart(uart1, c);
>
> Nix!

Objekte bekommen dann erst Sinn, wenn es sich um Dinge handelt, die zur 
Laufzeit entstehen, Zustand/Verhalten haben und wieder verschwinden. 
GUI-Elemente etwa, oder Objekte in Simulationen (wo OOP ja herkommt).

Bei statischen Objekten wie UARTs, die sich in Geräten normnalerweise 
nicht anlegen und verschwinden, ist das bloß syntaktischer Zucker.

von Bernd K. (prof7bit)


Bewertung
0 lesenswert
nicht lesenswert
Finde Dich mit dieser Schreibweise ab:
void lampe_an(lampe_t* this) {
    this->gpio->PSOR = this->bitmask; // oder so ähnlich
}

lampe_an(&lampe1);

fifo_push(&tx_fifo, 42);

//etc...

Es schreit zwar laut "ich bin C" aber besser oder schöner oder kürzer 
wirds in dieser Sprache nun mal nicht werden, egal wie viele 
Verrenkungen Du machst. Diese Notation ist ehrlich und macht keinen Hehl 
daraus was sie ist, auch OOP-Ablehner verstehen sofort intuitiv was das 
ist und hättens vielleicht sogar selbst genauso gemacht (obwohl es 
streng genommen tatsächlich ein Konzept von OOP implementiert).

: Bearbeitet durch User
von Bernd K. (prof7bit)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Objekte bekommen dann erst Sinn, wenn es sich um Dinge handelt, die zur
> Laufzeit entstehen,

Oder wenn es mehrere von der selben Sorte gibt, zum Beispiel 3 
identische UARTs die sich nur im Registeroffset unterscheiden. Dann 
macht man sich ein struct mit nem Zeiger aufs uart und den beiden fifos 
und eine handvoll Funktionen die auf so ein Struct anwendbar sind und 
fertig ist die Klasse mit ihren Methoden und man kann 3 Instanzen davon 
statisch erzeugen und benutzen.

: Bearbeitet durch User
von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:

> Oder wenn es mehrere von der selben Sorte gibt, zum Beispiel 3
> identische UARTs die sich nur im Registeroffset unterscheiden.

Dann übergibt man die UART-ID und erschlägt damit DRY genauso.

von Bernd K. (prof7bit)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Bernd K. schrieb:
>
>> Oder wenn es mehrere von der selben Sorte gibt, zum Beispiel 3
>> identische UARTs die sich nur im Registeroffset unterscheiden.
>
> Dann übergibt man die UART-ID und erschlägt damit DRY genauso.

Und wo willst Du die jeweils zwei (also insgesamt 6) Fifos unterbringen 
und vielleicht noch irgendwelchen zusätzlichen state?

In meinen Fall mach ich ne fifo-Klasse und ne UART-Klasse und jede 
UART-Instanz hält zwei Zeiger auf ihre beiden Fifo-Instanzen und den 
Zeiger auf die UART-Hardware.

: Bearbeitet durch User
von W.S. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Jens schrieb:
> ich möchte dann im code beispielsweise schreiben können:
>
>   Lampe.an();
>   Lampe.aus();
>   Lampe.init();

Natürlich geht sowas, jedoch in C mit ein bissel Umständen. Guck zu 
diesem Thema in die Lernbetty.

Ein Beispiel daraus:
#define RCST  const struct TMenuItem
struct TMenuItem
{ struct TRect R;                  /* die Koordinaten relativ zum Owner       */
  const struct TMenuItem *davor;   /* Listenverkettung: Item davor            */
  const struct TMenuItem *danach;  /* Listenverkettung: Item danach           */
  const struct TMenuItem *Owner;   /* Item, wo dieses enthalten ist           */
  const struct TMenuItem *Members; /* Liste der enthaltenen Items             */
  dword Flags;                     /* diverse Flag-Bits                       */
  void  *Data;                     /* Zeiger auf fallspezifische Daten        */
  void  (*OnKey)  (RCST* self, word *aKey);     /* wertet Tastendrücke aus    */
  void  (*OnEvent)(RCST* self, word *aEvent);   /* wertet Ereignisse aus      */
  void  (*Draw)   (RCST* self);    /* zeichnet sich und Members  */
};
[/]

Bemerke, daß die Quasi-Methoden hier explizit als 1. Argument den Zeiger auf "ihr" Objekt haben müssen (RCST* self), weil sie ja ansonsten nicht wissen können, wessen Methode sie gerade sind.
Benutzbar ist das dann etwa so:
[c]
extern void PanelKeyHandler   (RCST *self, word *aKey);
extern void PanelEventHandler (RCST* self, word *aEvent);
extern void PanelDrawProc     (RCST* self);

RCST ADCsee_Mainmenu =
{ /* l-t-r-b */ { 0, 0, 127, 159},
  /* davor  */  0,
  /* danach */  0,
  /* Owner  */  0,
  /* Members*/  &ADCsee_Batterie,
  /* Flags  */  opaque,
  /* *Data  */  (void*) &ADCsee_Mainmenu_focussed,
  /* OnKey  */  PanelKeyHandler,
  /* OnEvent*/  PanelEventHandler,
  /* Draw   */  PanelDrawProc
};

... usw.

So etwa geht das, wenn man Objekte in C formulieren will und selbige im 
Flash positionieren will, um keinen RAM dafür zu verplempern und auch 
keine Heapverwaltung einführen zu müssen.

W.S.

von A. S. (achs)


Bewertung
1 lesenswert
nicht lesenswert
Unglaublich schrieb:
> was ist da jetzt soviel toller als

Ich habe einige offensichtliche Vorteile aufgeführt. Hinzu kommt z.B. 
die Möglichkeit, einen Breakpoint zu setzen und einfach dry. Bei 
größeren Projekten  kommen weitere Vorteile hinzu, Stichwort Lesbarkeit. 
Da Code-Kopien aber per se böse sind, Lohnt es sich meist nicht, über 
den Unterschied von Copy Paste und automatisierten Kopien zu streiten.

Nop schrieb:
> Objekte bekommen dann erst Sinn, wenn es sich um Dinge handelt, die zur
> Laufzeit entstehen,

Genau. Da macht OOP Sinn. Konkrete Dinge hingegen brauchen meist 
konkreten Code.

von Nop (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Bernd K. schrieb:

> Und wo willst Du die jeweils zwei (also insgesamt 6) Fifos unterbringen

Das geht mit ein paar typedefs, und am Ende habe ich dann ein Array, 
dessen erster Index gerade die UART-ID ist.

von Markus F. (mfro)


Bewertung
1 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Finde Dich mit dieser Schreibweise ab:
> void lampe_an(lampe_t* this) {
>     this->gpio->PSOR = this->bitmask; // oder so ähnlich
> }

So schreibt man das nur, wenn man ganz sicher weiß, daß den Code niemals 
ein C++ Compiler zu sehen bekommen soll (also lieber gar nicht). 
Ansonsten nimmt man eher (z.B.) "self" oder man muss im Fall der Fälle 
alles nochmal anfassen.

von DS (Gast)


Bewertung
0 lesenswert
nicht lesenswert
typedef struct
{
    uint8_t Helligkeit;
    void (*an)(void);
    void (*aus)(void);
} lampe_t;

lampe_t Glühobst, Funzel;


int main(void)
{
    Glühobst.an();
    Funzel.an();
}


Wie bekommt man es hin, bzw. ist es möglich das *.an() Helligkeit 
jeweils auf 255 setzt?

Danke

Gruß

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:

> Ansonsten nimmt man eher (z.B.) "self"

Ich würd ja einen aussagefähigen Namen nehmen, in dem Fall 
beispielsweise einfach "lampe". Oder noch mit ungarischen Gewürzen 
davor.

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
DS schrieb:
> Wie bekommt man es hin, bzw. ist es möglich das *.an() Helligkeit
> jeweils auf 255 setzt?

Ohne Self-Pointer und ohne C++ nur mit einer eigenen an-funktion je 
Lampe. Also nichts für Anfänger.

von DS (Gast)


Bewertung
0 lesenswert
nicht lesenswert
>>Also nichts für Anfänger.

wieso, bin nur neugierig, bis jetzt ist doch noch nichts schlimmes dabei 
:-)

>>mit einer eigenen an-funktion je Lampe

das ist ja schade.

Gibt es in C wirklich keine Möglichkeit für die Funktion an() 
"herauszufinden" von wo sie aufgerufen wurde um den richtigen Speicher 
zu beackern?

Gruß
DS

von Nop (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
DS schrieb:

> Gibt es in C wirklich keine Möglichkeit für die Funktion an()
> "herauszufinden" von wo sie aufgerufen wurde um den richtigen Speicher
> zu beackern?

Der wesentliche Unterschied zwischen einer Methode eines Objektes (C++) 
und einem Funktionspointer in einem struct (c) ist der, daß die 
aufgerufene Funktion in letzterem Falle keine Information hat, zu 
welchem Objekt das jetzt gehört. Bei objektorientierten Sprachen bekommt 
die Methode unter der Haube einen versteckten Pointer auf das Objekt, in 
C hingegen nicht.

In C ist diese Funktion aus ihrer eigenen Sicht einfach nur eine 
void-void-Funktion. Der einzige Weg, wie so eine Funktion an 
Informationen von außerhalb gelangen kann, sind globale Variablen. 
Demzufolge könntest Du natürlich vor dem Aufruf eine globale Variable 
setzen, die in der an()-Funktion abgefragt wird, aber das wäre 
superhäßlich.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Nop schrieb:
> Der wesentliche Unterschied zwischen einer Methode eines Objektes (C++)
> und einem Funktionspointer in einem struct (c) ist der, daß die
> aufgerufene Funktion in letzterem Falle keine Information hat, zu
> welchem Objekt das jetzt gehört. Bei objektorientierten Sprachen bekommt
> die Methode unter der Haube einen versteckten Pointer auf das Objekt, in
> C hingegen nicht.

Grundsätzlich hast du natürlich vollkommen recht!

Allerdings ist unser Gcc C++ soweit entwickelt, dass das nicht mehr 
unter allen Umständen so ist. Selbst die Referenz, also der Halter einer 
Instanz, und damit auch this kann u.U. vollständig weg optimiert werden.

Das macht C++ auf µC etwas praktikabler, weniger Speicher/Ram fressend.

Erst wenn das Objekt Eigenschaften(Variablen im Bauch) hat, dann führt 
kein Weg mehr an this vorbei.

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Selbst die Referenz, also der Halter einer
> Instanz, und damit auch this kann u.U. vollständig weg optimiert werden.

Das schon, aber der Punkt ist, daß überhaupt was DA ist, was ggf. auch 
wegoptimiert werden kann.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
DS schrieb:
> Gibt es in C wirklich keine Möglichkeit für die Funktion an()
> "herauszufinden" von wo sie aufgerufen wurde um den richtigen Speicher
> zu beackern?

auch C++ "findet" das nicht raus. Der this-Zeiger wird einfach 
"unsichtbar" mitgegeben und ist implizit Bestandteil des 
Methodenaufrufs.

Die ersten C++ Compiler haben (als Präprozessor) genauso funktioniert. 
Vom Präprozessor wurde C-Code erzeugt und das Ergebnis schlussendlich 
von einem C-Compiler verwurstet.

Allerdings sollte man wohl fairerweise sagen, dass dieses C++ mit 
heutigem nicht wirklich viel gemein hatte.

Man kann Objektorientierung in C noch viel weiter treiben. Ob das 
allerdings sinnvoll ist, ist eine andere Frage: Anfänger verwirrt man 
damit nur und alle anderen sollten lieber gleich C++ nehmen, das ist 
schliesslich dafür gemacht.

von Bernd K. (prof7bit)


Bewertung
1 lesenswert
nicht lesenswert
Markus F. schrieb:
> Bernd K. schrieb:
>> Finde Dich mit dieser Schreibweise ab:
>> void lampe_an(lampe_t* this) {
>>     this->gpio->PSOR = this->bitmask; // oder so ähnlich
>> }
>
> So schreibt man das nur, wenn man ganz sicher weiß, daß den Code niemals
> ein C++ Compiler zu sehen bekommen soll (also lieber gar nicht).

Nö, das genaue Gegenteil ist der Fall.

In C++ heißt dieser Pointer ebenfalls this, also kann ich beim Portieren 
von C nach C++ das meiste einfach so lassen wie es ist.

> oder man muss im Fall der Fälle
> alles nochmal anfassen.

Anfassen muss ich es eh wenn ich es nach C++ portiere aber wenn der 
this-Pointer zufällig in weiser Voraussicht schon this heißt muss ich 
weniger anfassen.

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
-1 lesenswert
nicht lesenswert
W.S. schrieb:
> Ein Beispiel daraus:

Es ist ja schön für Dich, daß Du ne Menüsteuerung programmiert hast. 
Aber für nen Anfänger ist es nur sehr schwer, daraus Erkenntnisse für 
völlig andere Aufgaben abzuleiten.
Beispiele sollten einfach sein und nicht hoch komplex.

W.S. schrieb:
> Bemerke, daß die Quasi-Methoden hier explizit als 1. Argument den Zeiger
> auf "ihr" Objekt haben müssen (RCST* self), weil sie ja ansonsten nicht
> wissen können, wessen Methode sie gerade sind.

Dieser Satz sagt mir, daß C++ überhaupt gar nichts für mich ist. Ich hab 
nicht mal die allerkleinste Idee, was er bedeuten könnte.

W.S. schrieb:
> So etwa geht das, wenn man Objekte in C formulieren will

Das mit den Objekten werde ich daher hintanstellen.

von Peter D. (peda)


Bewertung
-1 lesenswert
nicht lesenswert
Bernd K. schrieb:
> In meinen Fall mach ich ne fifo-Klasse und ne UART-Klasse und jede
> UART-Instanz hält zwei Zeiger auf ihre beiden Fifo-Instanzen und den
> Zeiger auf die UART-Hardware.

Ja, sowas wäre mal als praktisches Beispiel gut zu gebrauchen.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Nö, das genaue Gegenteil ist der Fall.

Quatsch.

Wenn der C "this"-Pointer "self" heisst, geht das Ding völlig 
unverändert durch den C++ Compiler und der Code läuft sofort so wie er 
als C-Programm lief.

Wenn er "this" heisst, hagelt's erstmal Fehlermeldungen ohne Ende.

von Bernd K. (prof7bit)


Bewertung
1 lesenswert
nicht lesenswert
Markus F. schrieb:
> Quatsch.

Selber Quatsch

> Wenn der C "this"-Pointer "self" heisst, geht das Ding völlig
> unverändert durch den C++ Compiler und der Code läuft sofort so wie er
> als C-Programm lief.

Warum sollte ich eine C Datei mit dem C++ Compiler kompilieren wollen? 
Wenn ich C++ draus machen will dann mach ich C++ draus und dann hilft es 
wenn ich große Brocken einfach 1:1 verwenden kann weil this schon this 
heißt.

> Wenn er "this" heisst, hagelt's erstmal Fehlermeldungen ohne Ende.

Nein, denn warum sollte ich den falschen Compiler verwenden, das ist 
absurd!

von W.S. (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Nop schrieb:
> Objekte bekommen dann erst Sinn, wenn es sich um Dinge handelt, die zur
> Laufzeit entstehen, Zustand/Verhalten haben und wieder verschwinden.
> GUI-Elemente etwa, oder Objekte in Simulationen (wo OOP ja herkommt).
>
> Bei statischen Objekten wie UARTs, die sich in Geräten normnalerweise
> nicht anlegen und verschwinden, ist das bloß syntaktischer Zucker.

Naja, nicht ganz so. Objekte haben ihren Sinn dort, wo sie aus reiner 
Software bestehen, die verwaltet werden müssen.Bestes Beispiel sind 
grafische Kringel auf'm Bildschirm, Menü-Elemente und so. Auch dann, 
wenn das Menü bereits zur Entwurfszeit feststeht und folglich im Flash 
angeordnet werden kann.

Bei aller Art von Hardware hast du hingegen völlig Recht, da ist es nur 
ne unnötige, sinnlose und ressourcenfressende Soße über das eigentliche 
Ding gekippt.



Bernd K. schrieb:
> Oder wenn es mehrere von der selben Sorte gibt, zum Beispiel 3
> identische UARTs die sich nur im Registeroffset unterscheiden. Dann
> macht man sich ein struct mit nem Zeiger aufs uart

Ach nö.

Du hast fast nirgendwo drei exakt gleiche UART's, denn bei genauerem 
Hingucken unterscheiden die sich ja doch, benötigen unterschiedliche 
ISR, hängen an unterschiedlichen System-Bussen usw.

Deswegen mußt du schlußendlich alles, was du so schön zusammengefaßt zu 
haben glaubst, innen drin wieder auseinanderfummeln.

Ich hab das alles schon vor Jahren durch gehabt, deswegen meine deutlich 
bessere Version mit dem hier schon mal geposteten gio.c, was nach oben 
hin für alle solche Datenströme ein einheitliches Interface bildet und 
nach unten hin von den tatsächlichen jeweiligen Lowlevel-Treibern 
getrennt ist.
Etwas so von oben:
extern void   String_Out (char* P, word wo);
wobei 'wo' eben ein Handle für den gewünschten Datenstrom ist. So geht 
das deutlich besser als mit deiner Idee und den Zeigern.

W.S.

von W.S. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Peter D. schrieb:
> Dieser Satz sagt mir, daß C++ überhaupt gar nichts für mich ist. Ich hab
> nicht mal die allerkleinste Idee, was er bedeuten könnte.

Das hat überhaupt nichts mit C++ zu tun! Sowas ist immer und in jeder 
Programmiersprache notwendig. Lerne mal lieber wieder Pascal und 
programmiere dir was mit Lazarus. Das hilft für's Verständnis.

Also mal zu deiner Erleuchtung:
Objekte haben drei Dinge:
- Eigenschaften (properties)
- Methoden (methods)
- und ihr Innenleben, was niemanden draußen etwas angeht.

Nun stelle dir mal drei instantiierte Objekte derselben Klasse vor. Zum 
Beispiel drei Menüeinträge. Einer ist "rauf" der nächste "runter" der 
dritte "hinein". Alle diese drei Objekte haben dieselben Methoden, denn 
sie sind ja von gleicher Klasse. Wie soll jetzt so eine Methode 
erkennen, als wessen Methode sie gerade aufgerufen wird?
Also
rauf.ZeichneDich;
runter.ZeichneDich;
hinein.ZeichneDich;
rufen alle die gleiche Methode klassenname.ZeichneDich auf.
Ganz klar, der Compiler fügt bei jedem Aufruf einer Methode zu den in 
der Typdeklaration angegebenen Argumenten eines hinzu: den Zeiger auf 
das aktuelle Objekt. Damit weiß die Methode, auf welches Objekt und 
dessen Properties und innere Daten es zugreifen muß.

Ist doch eigentlich ganz logisch und auch leicht zu verstehen.

W.S.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Nein, denn warum sollte ich den falschen Compiler verwenden, das ist
> absurd!

Warum ist das absurd?

Jeder (na gut, 99,9% von denen, die erst nachdenken) mit einigermassen 
nennenswerter, existierender Codebasis wird die beim Umstieg von C auf 
C++ nicht einfach wegschmeissen und neu programmieren, sondern den (ja 
nicht ganz unabsichtlich möglichen) "weichen Migrationsweg" wählen.

Da ist man dann ganz froh, wenn der Compiler sich nicht an so 
Kleinigkeiten wie "this" und "class" aufhängt sondern gleich zur Sache 
kommt, wenn der Code zum ersten mal durch die C++-Mühle gedreht wird.

von MeineZweiCent (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
>> Wenn der C "this"-Pointer "self" heisst, geht das Ding völlig
>> unverändert durch den C++ Compiler und der Code läuft sofort so wie er
>> als C-Programm lief.
>
> Warum sollte ich eine C Datei mit dem C++ Compiler kompilieren wollen?
> Wenn ich C++ draus machen will dann mach ich C++ draus und dann hilft es
> wenn ich große Brocken einfach 1:1 verwenden kann weil this schon this
> heißt.
>
>> Wenn er "this" heisst, hagelt's erstmal Fehlermeldungen ohne Ende.
>
> Nein, denn warum sollte ich den falschen Compiler verwenden, das ist
> absurd!

Kennst du die Suchen und Ersetzen Funktion deiner IDE schon? Du kannst 
die "this" wie vorgeschlagen "self" nennen, dann kompiliert dein 
Programm für C und C++. Wenn du aber das this nachträglich willst, gehst 
du in deiner IDE auf global suchen "self" ersetzen durch "this" und 
schon hast du wieder deinen für c++ nicht kompilierbaren "this" code. 
Dann kannst du die "großen Brocken" immernoch auf C++ umstellen ;)

von Markus F. (mfro)


Bewertung
1 lesenswert
nicht lesenswert
Du hast ja vielleicht Tricks drauf.

Ich vermeide lieber C++-Schlüsselworte in C-Code.

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Objekte haben drei Dinge:
> - Eigenschaften (properties)
> - Methoden (methods)
> - und ihr Innenleben, was niemanden draußen etwas angeht.

Nur zur Übersetzung für C-onlys:
Objekt = struct (class), genauer: eine Variable davon (Instanz)

Methode=Funktion (in Pascal auch als Prozedur, darum ein anderer Begriff 
notwendig)

Eigenschaft:von außen zugreifbares struct-element

Innenleben: nach außen unsichtbares struct-element

von Bernd K. (prof7bit)


Bewertung
0 lesenswert
nicht lesenswert
MeineZweiCent schrieb:
> Kennst du die Suchen und Ersetzen Funktion deiner IDE schon? Du kannst
> die "this" wie vorgeschlagen "self" nennen

Nein, warum sollte ich das machen? Ich habs von Anfang an absichtlich 
this genannt weil das der übliche Name dafür ist, denn sollte ich jemals 
auf die Idee kommen wollen es nach C++ portieren wollen kann das 
schonmal so bleiben und ich muss überhaupt nichts umbenennen. Und 
solange ich es nicht portiert habe bekommt es auch kein C++ Compiler 
jemals zu sehen, wozu auch? Sprech ich chinesisch oder warum ist das so 
schwer zu verstehen?

: Bearbeitet durch User
von Bernd K. (prof7bit)


Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Du hast ja vielleicht Tricks drauf.
>
> Ich vermeide lieber C++-Schlüsselworte in C-Code.

Das macht Sinn an Stellen wo sie eine andere Bedeutung haben, hier aber 
(bei this) bleibt die Bedeutung exakt identisch, es muß hinterher im 
fertig portierten Code eh this heißen, also warum erst umbenennen und 
dann wieder zurückumbenennen, das ist vollkommen absurd.

Ich weiß auch nicht wie Du auf die fixe Idee kommst es würde auch nur 
den geringsten Sinn ergeben oder irgendwer würde auf die Idee kommen 
wollen  C-Dateien durch den C++ Compiler jagen wollen wenn er doch einen 
C Compiler hat.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> In meinen Fall mach ich ne fifo-Klasse und ne UART-Klasse und jede
> UART-Instanz hält zwei Zeiger auf ihre beiden Fifo-Instanzen und den
> Zeiger auf die UART-Hardware.

Möchtest Du diesen Code nicht auch mal zeigen?
Das wäre wenigstens mal ein praktisches Beispiel, was man nachvollziehen 
könnte und den Einstieg in C++ ermöglichen würde.
Bisher habe ich hier immer nur Codebruchstücke gesehen, mit denen man 
nichts anfangen kann.

von Bernd K. (prof7bit)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Das wäre wenigstens mal ein praktisches Beispiel, was man nachvollziehen
> könnte und den Einstieg in C++ ermöglichen würde.

Die sind aber in purem C geschrieben, also nichts zum C++ lernen.

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Die sind aber in purem C geschrieben, also nichts zum C++ lernen.

Weil Du von Klassen sprichst, dachte ich, es wäre C++.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Das wäre wenigstens mal ein praktisches Beispiel, was man nachvollziehen
> könnte und den Einstieg in C++ ermöglichen würde.

Ich könnte dir da meinen C++ Ersatzstoff für die Arduino pinMode() und 
digitalxxx() Funktionen anbieten.......

von Cyblord -. (cyblord)


Bewertung
-1 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Peter D. schrieb:
>> Das wäre wenigstens mal ein praktisches Beispiel, was man nachvollziehen
>> könnte und den Einstieg in C++ ermöglichen würde.
>
> Ich könnte dir da meinen C++ Ersatzstoff für die Arduino pinMode() und
> digitalxxx() Funktionen anbieten.......

Es wurde nicht nach abschreckenden Beispielen gefragt...

von C. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Arduino F. schrieb:
> Ich könnte dir da meinen C++ Ersatzstoff für die Arduino pinMode() und
> digitalxxx() Funktionen anbieten.......

Ein Teil dieser Antworten würde die Bevölkerung verunsichern


sorry musste sein

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Achim S. schrieb:
> Nur zur Übersetzung für C-onlys:
> Objekt = struct (class), genauer: eine Variable davon (Instanz)
>
> Methode=Funktion (in Pascal auch als Prozedur, darum ein anderer Begriff
> notwendig)
>
> Eigenschaft:von außen zugreifbares struct-element
>
> Innenleben: nach außen unsichtbares struct-element


Du hast dich als Übersetzer blamiert.

Eine Eigenschaft (property) eines Objektes ist eben NICHT mal bloß ein 
struct-element, auf was man von außen zugreifen kann. Es ist tatsächlich 
eine Eigenschaft und das ist was ganz anderes, weil der Zugriff darauf 
völlig anders ist als auf ein popliges Element eines ebenso popligen 
struct's.

Im Allgemeinen kann ein lesender Zugriff auf eine Eigenschaft so 
ziemlich direkt erfolgen, es gibt aber Ausnahmen. Ein schreibender 
Zugriff hingegen erfolgt eigentlich immer über spezielle 
Schreibfunktionen, weil ja das Ändern einer Eigenschaft nicht einfach 
ein Überschreiben eines struct-elementes ist, sondern das verhalten des 
Objektes beeinflußt.

Und Methoden sind eben auch was anderes als bloße Funktionen und 
Prozeduren. Ich will mich hier ja gar nicht über Abstammungen, virtuell 
oder nicht, Überladung, Neueinführung usw. auslassen.

Und das Innenleben eines Objektes ist auch weitaus mehr als bloß nach 
außen unsichtbares struct-element. Wer mehr darüber wissen will, sollte 
sich tatsächlich darüber belesen - hier wäre das zu sehr abgeschweift.

Hier geht es ja um die Frage, ob und wie man eine (eher primitive) Art 
von quasi-objektorientierter Programmierweise in C hinkriegen kann, also 
wie der TO sich dachte mit "Lampe.An();" und so.

Es ist lediglich bei Hardware-Angelegenheiten so, daß der Versuch, sowas 
in Objektform zu bringen, fast immer herzlich unsinnig ist, weil man 
damit weder etwas verbessert noch klarer faßbar macht. Das Gegenteil ist 
der Fall, denn der Aufwand, auf Hardware-Angelegenheiten eine nach 
Objekt-Programmierung riechende Obefläche draufzudrücken, steht im 
krassen Gegensatz zum erhofften Nutzen. Hab ich ja weiter oben schon 
ausgeführt.

Ich sag's mal plakativ:
Für Software gibt's objektorientierte Programmierung
Für Hardware gibt's Low Level Treiber.

W.S.

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
C. schrieb:
> Ein Teil dieser Antworten würde die Bevölkerung verunsichern

Das mag sein....

Aber dennoch folgt es recht gut der eingangs genannten Syntax!

// hier lampe Instanz definieren/anlegen


void setup()
{
  lampe.init();
}

void loop()
{
  lampe.setHigh(); // ein
// hier könnte ein delay stehen
  lampe.setLow(); // aus
// hier könnte ein delay stehen
}

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.