Forum: Mikrocontroller und Digitale Elektronik C Frage zu Funktionen


von Jens (Gast)


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. (Gast)


Lesenswert?

C ist ein C++! Eher setzeWert(&Lampe, 255);

von npn (Gast)


Lesenswert?

Curby23523 N. schrieb:
> C ist ein C++!

Was willst du damit sagen?

von Mike R. (thesealion)


Lesenswert?

Lampe.an() muss halt ein Pointer auf eine Funktion sein.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

npn schrieb:
> Was willst du damit sagen?

Dass bei ihm die Taste 'k' klemmt.

: Bearbeitet durch Moderator
von Waldfee (Gast)


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. (Gast)


Lesenswert?

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

von Waldfee (Gast)


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


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)


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. (Gast)


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)


Lesenswert?

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

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

von Markus F. (mfro)


Lesenswert?

so geht's doch prima (wenn man das unbedingt haben will):
1
#include <stdio.h>
2
3
void an(void)
4
{
5
    printf("an\n");
6
}
7
8
void aus(void)
9
{
10
    printf("aus\n");
11
}
12
13
struct lampe
14
{
15
    void (*an)(void);
16
    void (*aus)(void);
17
} lampe =
18
{
19
    &an,
20
    &aus
21
};
22
23
int main(int argc, char *argv[])
24
{
25
    lampe.an();
26
    lampe.aus();
27
}

Nach einem this-Pointer hat bislang keiner gefragt.

von CK (Gast)


Lesenswert?

Markus F. schrieb:
> Nach einem this-Pointer hat bislang keiner gefragt.

Erst wenn es zwei Lampen werden ^^

von Markus F. (mfro)


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:
1
...
2
struct lampe
3
{
4
    void (*an)(void);
5
    void (*aus)(void);
6
} lampe[] =
7
{
8
    {
9
        &an1,
10
        &aus1
11
    },
12
    {
13
        &an2,
14
        &aus2
15
    }
16
};
17
18
int main(int argc, char *argv[])
19
{
20
    lampe[0].an();
21
    lampe[1].aus();
22
}

von A. S. (Gast)


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)


Lesenswert?

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

von A. S. (Gast)


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)


Lesenswert?

Achim S. schrieb:
> uart1.put(c);

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

Nix!

von Nop (Gast)


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)


Lesenswert?

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

1
lampe_an(&lampe1);
2
3
fifo_push(&tx_fifo, 42);
4
5
//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)


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)


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)


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)


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:
1
#define RCST  const struct TMenuItem
2
struct TMenuItem
3
{ struct TRect R;                  /* die Koordinaten relativ zum Owner       */
4
  const struct TMenuItem *davor;   /* Listenverkettung: Item davor            */
5
  const struct TMenuItem *danach;  /* Listenverkettung: Item danach           */
6
  const struct TMenuItem *Owner;   /* Item, wo dieses enthalten ist           */
7
  const struct TMenuItem *Members; /* Liste der enthaltenen Items             */
8
  dword Flags;                     /* diverse Flag-Bits                       */
9
  void  *Data;                     /* Zeiger auf fallspezifische Daten        */
10
  void  (*OnKey)  (RCST* self, word *aKey);     /* wertet Tastendrücke aus    */
11
  void  (*OnEvent)(RCST* self, word *aEvent);   /* wertet Ereignisse aus      */
12
  void  (*Draw)   (RCST* self);    /* zeichnet sich und Members  */
13
};
14
[/]
15
16
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.
17
Benutzbar ist das dann etwa so:
18
[c]
19
extern void PanelKeyHandler   (RCST *self, word *aKey);
20
extern void PanelEventHandler (RCST* self, word *aEvent);
21
extern void PanelDrawProc     (RCST* self);
22
23
RCST ADCsee_Mainmenu =
24
{ /* l-t-r-b */ { 0, 0, 127, 159},
25
  /* davor  */  0,
26
  /* danach */  0,
27
  /* Owner  */  0,
28
  /* Members*/  &ADCsee_Batterie,
29
  /* Flags  */  opaque,
30
  /* *Data  */  (void*) &ADCsee_Mainmenu_focussed,
31
  /* OnKey  */  PanelKeyHandler,
32
  /* OnEvent*/  PanelEventHandler,
33
  /* Draw   */  PanelDrawProc
34
};
35
36
... 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. (Gast)


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)


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)


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)


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)


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. (Gast)


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)


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)


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 Einer K. (Gast)


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)


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)


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)


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)


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)


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)


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)


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)


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


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)


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)


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)


Lesenswert?

Du hast ja vielleicht Tricks drauf.

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

von A. S. (Gast)


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)


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)


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)


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)


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)


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 Einer K. (Gast)


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)


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)


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)


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 Einer K. (Gast)


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!

1
// hier lampe Instanz definieren/anlegen
2
3
4
void setup()
5
{
6
  lampe.init();
7
}
8
9
void loop()
10
{
11
  lampe.setHigh(); // ein
12
// hier könnte ein delay stehen
13
  lampe.setLow(); // aus
14
// hier könnte ein delay stehen
15
}

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.