Forum: PC-Programmierung C++ Sinn von dieser Codeabschnitt


von SamiDortmund (Gast)


Lesenswert?

Hallo Zusammen,


Programmiersprache ist C++.

es geht um folgende Deklaration:
1
typedef void(*t_fStateAlive)(void *, bool, int);
2
t_fStateAlive m_fupStateAlive;
Was will man damit errreichen?
Ist das Sinnvoll?

Diese ist in eine andere Funktion gebraucht:
1
vfuInitialize(int iAliveTimeout_p, int iCodePartition_p, t_fStateAlive fupStateAlive_p, void *pParent_p)

Danke

von Keiner N. (nichtgast)


Lesenswert?

Das kann gar kein C++ code sein. Wenn doch war der Programmierer 
schlecht :)


im Grunde wird mit den beiden Zeilen ein Funktionszeiger angelegt, dem 
man eine Funktion mit drei Argumenten und keinem Rückgabewert zuweisen 
kann.
1
typedef void(*t_fStateAlive)(void *, bool, int);  // ein typdef, damits "lesbarer" wird
2
t_fStateAlive m_fupStateAlive;  // Zeiger deklarieren

Jetzt kann man dem Zeiger eine Funktion geben und sie darüber aufrufen
1
void foo(void *one,bool two, int three){
2
    tuwas();
3
}
4
5
m_fupStateAlive=foo;
6
7
m_fupStateAlive("bla",true,5);

damit kann man einfach eine Funktion als Parameter übergeben. z.Bsp als 
Callback.

: Bearbeitet durch User
von SamiDortmund (Gast)


Lesenswert?

Keiner N. schrieb:
1
typedef void(*t_fStateAlive)(void *, bool, int);

Diese ist aber nirgendwo implementiert aber benutzt wird Sie durch diese 
Aufruf:
1
t_fStateAlive

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

SamiDortmund schrieb:
> Diese ist aber nirgendwo implementiert

Das ist ein typedef: damit wird ein Aliasname (t_fStateAlive) für
einen Typ angelegt ("Zeiger auf eine Funktion, die nichts zurück
gibt und drei Parameter übernimmt.  Der erste ist ein anonymer
Objektzeiger, der zweite ein "bool", der dritte ein "int".).

"Implementiert" wird dabei gar nichts.  Man könnte auch stets statt
des typedefs die vollständige Typ-Bezeichnung schreiben.

Gerade bei Funktionszeigern macht ein typedef die Sache häufig
übersichtlicher. Ohne diesen typedef müsste man die Variable so
definieren:
1
void (*m_fupStateAlive)(void *, bool, int);

Besonders, wenn man jetzt eine Funktion deklarieren will, die einen
solchen Zeiger zurückgibt, wird das ziemlich schnell sehr komplex.
Ein typisches Beispiel dafür ist die Bibliotheksfunktion "signal",
die einen Handler installieren kann und gleichzeitig den vorherigen
zurückgibt.

Ohne typedef:
1
void (*signal(int sig, void (*func)(int)))(int);

Mit typedef:
1
typedef void (*sig_t) (int);
2
3
sig_t signal(int sig, sig_t func);

: Bearbeitet durch Moderator
von SamiDortmund (Gast)


Lesenswert?

Vielen Dank für die ausführliche Antwort.

von SamiDortmund (Gast)


Lesenswert?

Ich habe noch einen Frage:

Wie kann einen C_Funktionszeiger in C++_Funktionszeiger?

Die Funktionszeiger in C hat keine Implementierung

Keiner N. schrieb:

> typedef void(*t_fStateAlive)(void *, bool, int);  // ein typdef, damits
> "lesbarer" wird
> t_fStateAlive m_fupStateAlive;  // Zeiger deklarieren
>
> Jetzt kann man dem Zeiger eine Funktion geben und sie darüber aufrufen
> void foo(void *one,bool two, int three){
>     tuwas();
> }
>
> m_fupStateAlive=foo;
>
> m_fupStateAlive("bla",true,5);

Danke in voraus

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

SamiDortmund schrieb:
> Wie kann einen C_Funktionszeiger in C++_Funktionszeiger?

Was willst Du mit dieser Frage fragen?


> Die Funktionszeiger in C hat keine Implementierung

Funktionszeiger haben nie eine Implementierung.

von Keiner N. (nichtgast)


Lesenswert?

So ganz verstehe ich die Frage nicht.


Der Zeiger funktioniert in C++ zumindest erst mal genau so. Wenn man es 
übersichtlicher machen wll, kann man std::function benutzen. Das sieht 
dann so aus:
1
#include <functional>
2
3
std::function<void(void*,bool,int) m_fupStateAlive;


Das ist um einiges Ausdrucksstärker als der C Funktionszeiger.

Meine Kritik bezog sich auf das void* in der Argumentenliste der 
Funktion. Das macht man in C++ nicht, weil es die Typprüfung aushebel. 
Dafür nimmt man Templates. Das würde aber warscheinlich einen größeren 
Umbau am Code erfordern.

Aber zum Schluss noch mal. Kannst du bitte deine Frage etwas genauer 
stellen? Du hast teilweise nur einen halben Satz hingeschrieben.

PS, wenn dein Englisch besser ist, dann schreib lieber so weiter :)

von SamiDortmund (Gast)


Lesenswert?

Ich möchte der C_Funktionzeiger in eine C++_funktionszeiger umändern.

Meine Frage ist:
Wie mache ich das?

Danke und sorry für die blöde Frage

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Keiner N. schrieb:

> std::function<void(void*,bool,int) m_fupStateAlive;

Ich glaube, da zieht es irgendwie. ;-)

> Das ist um einiges Ausdrucksstärker als der C Funktionszeiger.

Finde ich nicht.  Einfach eine andere Syntax.  Wenn man spitze Klammern
mehr mag als runde, dann ist das vielleicht besser …

SamiDortmund schrieb:
> Wie mache ich das?

Du benutzt ihn 1:1 weiter.

Das angesprochene Problem der Übergabe eines generischen Zeigers
(void *) kannst du nicht so trivial lösen.

von Keiner N. (nichtgast)


Lesenswert?

Das ist glaube dann nur eine Verständnisfrage.


Du hast folgende Konstrukte:
1
typedef void(*t_fStateAlive)(void *, bool, int);
2
t_fStateAlive m_fupStateAlive;
3
4
//und
5
6
vfuInitialize(int iAliveTimeout_p, int iCodePartition_p, t_fStateAlive fupStateAlive_p, void *pParent_p)

Alles was tu tun musst, ist eine Funktion mit dieser Signatur erstellen, 
die macht, was immer eine Funktion machen soll, die von vfuInitialize 
aufgerufen wird.

1
void meineAufgerufeneFunktion(void* daten, bool foo, int bar){
2
      tuWasAuchImmer();
3
}

Dann kannst du den Namen der Funktion einfach als Parameter  übergeben
1
 vfuInitialize(0, 0, meineAufgerufeneFunktion, NULL)

Was die Funktion machen soll kann ich dir natürlich nicht verraten. Das 
musst du wissen.

von Keiner N. (nichtgast)


Lesenswert?

Jörg W. schrieb:
> Keiner N. schrieb:
>
>> std::function<void(void*,bool,int) m_fupStateAlive;
>
> Ich glaube, da zieht es irgendwie. ;-)
>
>> Das ist um einiges Ausdrucksstärker als der C Funktionszeiger.
>
> Finde ich nicht.  Einfach eine andere Syntax.  Wenn man spitze Klammern
> mehr mag als runde, dann ist das vielleicht besser …

Ich finde den Ausdruck um eniges einfacher zu lesen. Mal im direkten 
Vergleich:
1
std::function<void(void*,bool,int)> m_fupStateAlive;
2
3
void(*t_fStateAlive)(void *, bool, int) m_fupStateAlive;
Funktionszeiger sind natürlich immer was, über das Anfänger gerne 
stolpern.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Keiner N. schrieb:
> Ich finde den Ausdruck um eniges einfacher zu lesen.

Glaube ich dir ohne weiteres.

Aber ich finde ihn keineswegs einfacher zu lesen.

Und nun?  Patt? ;-)

Es ist doch einfach nur eine Frage der Gewohn(t)heit, mehr nicht.  Ein
bisschen verquer muten Funktionszeiger auf den ersten Blick immer an.

ps: Deine zweite Variante ist allerdings falsch geschrieben.  Die
korrekte Version ohne typedef hatte ich oben geschrieben.

: Bearbeitet durch Moderator
von Keiner N. (nichtgast)


Lesenswert?

Jörg W. schrieb:

> ps: Deine zweite Variante ist allerdings falsch geschrieben.  Die
> korrekte Version ohne typedef hatte ich oben geschrieben.

Ach Verdammt :) Ich war so froh, dass std::function eingeführt wurde. 
Ich benutze zwar relativ häufig Funktionszeiger, aber mit diesem C-Style 
habe ich immer gehadert und musste sie immer "zusammenbasteln".

Vor allem diese fehlende Aufteilung von Datentyp und Bezeichner stört 
meinen Lesefluss (und merken kann ich es mir offensichtlich auch nicht 
:).

von SamiDortmund (Gast)


Lesenswert?

Ich danke euch

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Keiner N. schrieb:
> Vor allem diese fehlende Aufteilung von Datentyp und Bezeichner stört
> meinen Lesefluss (und merken kann ich es mir offensichtlich auch nicht
> :).

Das ist seit C++11 etwas besser geworden, da kann man das jetzt so 
machen:
1
using fStateAlive = void(*)(void *, bool, int);
Geht ähnlich auch für andere Dinge:
1
using MyArray = int[10];
2
using MyPtr = int*;

von Rolf M. (rmagnus)


Lesenswert?

Keiner N. schrieb:
> Vor allem diese fehlende Aufteilung von Datentyp und Bezeichner stört
> meinen Lesefluss (und merken kann ich es mir offensichtlich auch nicht
> nicht :).

Meinen Lesefluss stört es dagegen, wenn plötzlich direkt auf den 
Returntyp die Parameter folgen und dazwischen der Name fehlt. Es sieht 
völlig anders aus als ein Funktionskopf, und ich erwarte irgendwie, dass 
die Definition eines Funktionszeiger auch nahezu genauso aussieht wie 
bei einer Funktion.

Niklas G. schrieb:
> Geht ähnlich auch für andere Dinge:
> using MyArray = int[10];
> using MyPtr = int*;

Finde ich genauso eigenartig, weil die syntaktische Analogie zur 
Definition entsprechender Variablen verloren gegangen ist.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Rolf M. schrieb:
> Keiner N. schrieb:
>> Vor allem diese fehlende Aufteilung von Datentyp und Bezeichner stört
>> meinen Lesefluss (und merken kann ich es mir offensichtlich auch nicht
>> nicht :).
>
> Meinen Lesefluss stört es dagegen, wenn plötzlich direkt auf den
> Returntyp die Parameter folgen und dazwischen der Name fehlt. Es sieht
> völlig anders aus als ein Funktionskopf, und ich erwarte irgendwie, dass
> die Definition eines Funktionszeiger auch nahezu genauso aussieht wie
> bei einer Funktion.

Deshalb schreibt man ja auch

std::function<

davor. Damit ist der Lesefluß vorgewarnt.

von Daniel -. (root)


Lesenswert?

Funktionen waren in C und C++ nie first class. Das ist ein Grund dafür 
warum
Leute später im Code anderer über Funktionszeiger stolpern.
C++ hat doch jetzt auch Lambdas/Closures. Wobei der alte C typedef auch 
Ok ist.

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.