Discussion:
Vorteile von CallBack Funktionen ?
(zu alt für eine Antwort)
dieter_regenberg
2003-07-02 16:09:39 UTC
Permalink
Hallo,

kann mir mal Jemand die genaue Funktionsweise von CallBack Funktionen
erklären.
Welchen Vorteil bzw. Nachteil hat die Verwendung solcher Funktinen unter C?

Gruss

Dieter
Stefan Ram
2003-07-02 18:10:41 UTC
Permalink
Post by dieter_regenberg
kann mir mal Jemand die genaue Funktionsweise von CallBack Funktionen
erklären.
Es gibt in C keine "call back functions" im Sinne der
Sprachnorm ISO/IEC 9899:1999 (E).

Es ist eine ausserhalb der Sprachnorm uebliche Konvention,
eine bestimmten Verwendung von Funktionsangaben so zu bezeichen.

In diesem Sinne ist eine "call back function" eine Angabe "A",
die (direkt oder indirekt) eine bestimmten Funktion "f" angibt
und die (direkt oder indirekt) als Argument an eine Funktion "g"
uebergeben wird, so dass es der Funktion "g" dann moeglich ist,
die Funktion "f" zu aktivieren. (Die Angabe "A" ist oft ein
Funktionszeiger.)
Post by dieter_regenberg
Welchen Vorteil bzw. Nachteil hat die Verwendung solcher Funktinen unter C?
Vorteil: groessere Flexibilitaet und Abstraktion.
Nachteil: groessere Komplexitaet und Abstraktion.
Helmut Leitner
2003-07-02 19:57:06 UTC
Permalink
Post by dieter_regenberg
Hallo,
kann mir mal Jemand die genaue Funktionsweise von CallBack Funktionen
erklären.
Man kann damit eine bestimmte Klasse von wiederverwendbaren Funktionen schreiben.

Ein Beispiel aus meiner Library:

ER DirFindFileCall(CH *dir,CH *fspec,ER (*f)(CH *dir,CH *fnam,FILEINFO *fb),IN flags);

Diese Funktion durchsucht einen Verzeichnisbaum nach Dateien und/oder Verzeichnissen
und ruft mit jeder gefundenen Datei die Funktion f auf. Z. B.

DirFindFileCall("C:\\TEST","*.c",test,DFFC_FILES|DFFC_RECURSE);

Mit der Funktion

ER test(CH *dir,CH *fnam,FILEINFO *fb) {
printf("%s\%s %ld\n",dir,fnam,fb->size);
}

würde eine Liste aller C-Files in dem Verzeichnisbaum ausgegeben. Es könnten jedoch
beliebige andere Funktionen verwendet werden, um alle File zu löschen, zu konvertieren
oder eine interne Datenstruktur damit zu füllen.

Ein anderes Beispiel ist die Standardfunktion qsort.
Post by dieter_regenberg
Welchen Vorteil bzw. Nachteil hat die Verwendung solcher Funktinen unter C?
Vorteil: wie immer. Wenn man damit ein Problem einfach lösen kann.

Nachteil in C: Es kann leicht sein, dass man irgendwelche zusätzlichen Parameter braucht,
die in der Parameterliste von f nicht vorgesehen sind. Da bleibt dann nur der Weg, diese
Parameter als globale Variablen zugänglich zu machen (wobei der Code dann nicht reentrant
wird).

Modernere Sprachen mit "Closures" sind flexibler, in D kann man z. B. schreiben:

char [][] DirFindFile(char [] dir,char [] fspec, int flags)
{
char [][] files;

DirFindFileCall(dir,fspec,
delegate int (char [] dir, char [] fnam, WIN32_FIND_DATA *b)
{
files ~= (dir ~ fnam);
return 0;
}
,flags
);
return files;
}

Hier wird die Funktion (der Code) praktisch direkt in die Parameterliste geschrieben,
dieser greift auf den darüber im Rahmen der Funktion definieren Array files zu.


--
Helmut Leitner ***@hls.via.at
Graz, Austria www.hls-software.com
Bodo Thiesen
2003-07-02 22:12:57 UTC
Permalink
Post by Helmut Leitner
Post by dieter_regenberg
Welchen Vorteil bzw. Nachteil hat die Verwendung solcher Funktinen unter C?
Man kann damit Dinge machen, die man ohne nicht (oder nur mit
unverhältnismäßig höherem Aufwand) realisieren könnte?
Post by Helmut Leitner
Nachteil in C: Es kann leicht sein, dass man irgendwelche zusätzlichen
Parameter braucht, die in der Parameterliste von f nicht vorgesehen sind.
Da bleibt dann nur der Weg, diese Parameter als globale Variablen zugänglich
zu machen (wobei der Code dann nicht reentrant wird).
Wie? Warum? Schonmal was von void * gehört? Das war übrigend genau /der/
Fall, in dem ich void * /überhaupt/ akzeptiere... (Siehe irgendeinen Artikel
des letzten Monats von mir...)
Ist hier OffTopic. Wenn wir D wollen, gehen wir nach dang und starten
einen RfD für de.comp.lang.d

Gruß, Bodo
--
MS Outlook Express?->[DE: http://piology.org/ILOVEYOU-Signature-FAQ.html]

@@@@@ GEGEN TCG aka. TCPA: @@@@@ [DE: http://www.againsttcpa.com]
Probleme mit Spam? [EN: http://www.spamhaus.org/globalremove.html]
Claus Reibenstein
2003-07-03 15:36:58 UTC
Permalink
Post by Bodo Thiesen
Post by Helmut Leitner
Nachteil in C: Es kann leicht sein, dass man irgendwelche zusätzlichen
Parameter braucht, die in der Parameterliste von f nicht vorgesehen sind.
Da bleibt dann nur der Weg, diese Parameter als globale Variablen zugänglich
zu machen (wobei der Code dann nicht reentrant wird).
Das ist kein Nachteil von C, auch keiner in C. Das ist ein
grundsätzlicher Nachteil von Callback-Funktionen. Allerdings ist dies
kein unlösbares Problem.
Post by Bodo Thiesen
Wie? Warum? Schonmal was von void * gehört?
Erspar mir bitte solch pupertäres Geschwafel
Diese unqualifizierte Antwort ist keinen Deut besser. Im Gegenteil.

Außerdem hat Bodo mit seinem "pupertären" (Du meist sicher pubertären)
"Geschwafel" gar nicht so unrecht.
mit ein bisschen Glück habe
ich schon mit "void *" gearbeitet als du noch gar nicht geboren warst.
Was macht Dich glauben, Bodo sei jünger als 14 Jahre?
An qsort wird die Tabelle mit "void *" übergeben, aber wenn du zum Sortieren
irgendwelche zusätzlichen Hilfsdaten benötigst, dann kannst du die Callback-
Parameterliste für das qsort nicht erweitern.
Ist auch nicht nötig.
Das ist besonders lästig, weil nicht einmal ein Offset-Parameter vorgesehen
ist. Gäbe es den, dann könnte man wenigstens für typische Sortierungen (z. B.
nach double aufsteigend) mit einer einzigen Callback-Funktion auskommen. So
muss man praktisch für jede Struktur, die man sortieren will, eine eigene
Callback-Funkton schreiben oder den Offset global beisteuern.
Das ist immer noch besser, als für jede Struktur eine eigene
Sortierfunktion schreiben zu müssen. Im Übrigen lässt sich dieses
Problem elegant mittels eines einfachen Wrappers lösen.

Gruß. Claus
Helmut Leitner
2003-07-04 08:00:39 UTC
Permalink
(zu Bodo)
mit ein bisschen Glück habe
ich schon mit "void *" gearbeitet als du noch gar nicht geboren warst.
Was macht Dich glauben, Bodo sei jünger als 14 Jahre?
Meinst du, dass man vor C89 nicht mit "void *" arbeiten konnte. Gefühlsmäßig
würde ich sagen, dass verschiedene Compiler das auch vorher schon konnten.

Kozeptionell hat "void *" nicht neues gebracht. Alles was "void *" kann, hat
man vorher mit "char *" und casts genauso gemacht. Nur weniger "schön".
--
Helmut Leitner ***@hls.via.at
Graz, Austria www.hls-software.com
Helmut Leitner
2003-07-04 07:56:58 UTC
Permalink
Post by Bodo Thiesen
Post by Helmut Leitner
Post by dieter_regenberg
Welchen Vorteil bzw. Nachteil hat die Verwendung solcher Funktinen unter C?
Man kann damit Dinge machen, die man ohne nicht (oder nur mit
unverhältnismäßig höherem Aufwand) realisieren könnte?
Post by Helmut Leitner
Nachteil in C: Es kann leicht sein, dass man irgendwelche zusätzlichen
Parameter braucht, die in der Parameterliste von f nicht vorgesehen sind.
Da bleibt dann nur der Weg, diese Parameter als globale Variablen zugänglich
zu machen (wobei der Code dann nicht reentrant wird).
Wie? Warum? Schonmal was von void * gehört?
Erspar mir bitte solch pupertäres Geschwafel...mit ein bisschen Glück habe
ich schon mit "void *" gearbeitet als du noch gar nicht geboren warst.
Das glaube ich nicht.
Wir können's ja nachrechnen, wenn du Lust dazu hast.

Zur Lösung der von dir angedeutenden Problemstellung hat man "void *" übrigens
nie gebraucht. In den 80-er Jahren hat man halt auf "char *" gecastet und
das gleiche ein bisschen weniger schön und weniger sicher erreicht.
1. Ist das, was ich damit angedeutet habe, elementäres C, und wenn Du
tatsächlich nicht selber auf diese Idee kommst, kann ich
2. nur davon ausgehen, daß Du entweder erst seit weniger als einem Jahr
in C programmierst (dafür aber schon einige Jahre Erfahrung mit einer
anderen Programmiersprache hast, die einen mit Zeigern konfrontiert),
oder Du insgesamt maximal seit ein paar Jahren überhaupt programmierst.
Ich programmiere seit 1983 in C. 1979 habe ich mein erstes Geld mit einem
Softwareprojekt verdient. Und seit 1988 bin ich als SW-Entwickler selbständig
und mache ca. 1/3 meines Umsatzes in C.

Emprisch gesehen muss also irgendwo in deinen Schlußfolgerungen ein Wurm sein.
Deine dunklen Andeutungen über die Problemlösungkapazität von "void *" im Bezug
auf die Frage des OP kann ich nicht nachvollziehen (bin kein Gedankenleser).
Post by Bodo Thiesen
Das war übrigend genau /der/
Fall, in dem ich void * /überhaupt/ akzeptiere... (Siehe irgendeinen Artikel
des letzten Monats von mir...)
Das geht aber nur beschränkt (nämlich wenn du den "Caller" in der Hand hast).
Wenn ich den Caller in der Hand habe, lasse ich mir keinen void *
übergeben, sondern lege die Struktur für den Caller fest.
Nicht wenn das Interface abstrakter sein soll.
An qsort wird die Tabelle mit "void *" übergeben, aber wenn du zum Sortieren
irgendwelche zusätzlichen Hilfsdaten benötigst, dann kannst du die Callback-
Parameterliste für das qsort nicht erweitern.
qsort hat den Nachteil nur Elemente gleicher Größe sortieren zu können.
Das habe ich nicht gesagt und nicht gemeint.
void * hash=malloc(sizeof(void *) * 3);
assert(hash);
hash[0]="Hallo";
hash[1]="du";
hash[2]="da!";
qsort(hash,3,sizeof(void *),compare);
Da werden Elemente unterschiedlicher Größe sortiert. (BTW: Dies ist nur
ein Beispiel.)
Du löst ein triviales (ein sogenanntes Strohmann-) Problem...

Ein beliebter Foren-Diskussions-Trick. Man wirft ein seitwärts vom Thema
liegendes Problem auf, das trivial und elegant gelöst wird (was aber eh
jeder weiß) und versucht dadurch Kompetenz zu gewinnen...
Das ist besonders lästig, weil nicht einmal ein Offset-Parameter vorgesehen
ist. Gäbe es den, dann könnte man wenigstens für typische Sortierungen (z. B.
nach double aufsteigend) mit einer einzigen Callback-Funktion auskommen.
struct sort_struct {
int offset;
void * ptr;
};
(Die erhöhte Laufzeit durch das initialisieren des Arrays fält bei
hinreichend großen Arrays überhaupt nicht mehr auf, und bei kleinen
kann man es andererseits vernachlässigen - außer es passiert in einer
Schleife...)
Es ist klar, dass es Work-Arounds gibt. Darum ging es aber nicht.

Der OP wollte wissen, welche Vor- und Nachteile C-Callbacks haben.

Wer C religiös verteidigen will, kann natürlich sagen, dass C-Callbacks
keine Nachteile haben, dass C keine Schwächen hat, dass C die beste
aller Sprachen ist ...

... und damit habe ich nicht mal ein emotionales Problem, weil C für mich
nach wie vor mein Lieblingssprache ist. Aber ich bin nicht blind verliebt.
So
muss man praktisch für jede Struktur, die man sortieren will, eine eigene
Callback-Funkton schreiben oder den Offset global beisteuern.
Offset global löst das Thread-Save-Problem nicht. Die unterschiedlichen
Callback-Funktionen schon.
Hab ich doch gesagt!? ;-)
Ansonsten könnte ich Dir noch das Inferface
void sortx(
void *arg,
int first,
int last,
int myownuse,
int maxownuse,
int (*compare)(void*,int,int),
void (*swap )(void*,int,int),
void (*average)(void*,int,int,int)
);
Ist sicher ein universelleres Interface als qsort. Es ist nicht das erste
solche alternative Interface das ich sehe und es zeigt, dass qsort eben
seine Schwächen hat. Andererseits sehe auch in deinem Interface Schwächen,
aber API-Design ist ja nicht das Thema.
Herauszufinden, wie Deine allgemeine double-Sort Callback-Funktion aussehen
könnte, das überlasse ich jetzt Dir, dann kannst Du mal - entgegen meiner
Behauptung von weiter oben - beweisen, doch Ahnung von C zu haben.
Das meine ich mit pubertär: das Bedürfnis zu haben, hier was zu beweisen.
Ich habe das Bedürfnis nicht.
Post by Bodo Thiesen
Ist hier OffTopic. Wenn wir D wollen, gehen wir nach dang und starten
einen RfD für de.comp.lang.d
Ein kleiner Sprachvergleich wird wohl erlaubt sein, oder willst
du als "Scheuklappen-Bodo" in die Geschichte eingehen?
char [][] DirFindFile(char [] dir,char [] fspec, int flags)
{
char [][] files;
DirFindFileCall(dir,fspec,
delegate int (char [] dir, char [] fnam, WIN32_FIND_DATA *b)
{
files ~= (dir ~ fnam);
return 0;
}
,flags
);
return files;
}
Was ist da der Unterschied zu
char * * files;
int delegate (char * dir, char * fnam, WIN32_FIND_DATA *b) {
files ~= (dir ~ fnam); /* Müsste noch sinnvoll angepasst werden...
return 0;
}
char * * DirFindFile(char * dir,char * fspec, int flags) {
DirFindFileCall(dir,fspec,delegate,flags);
return files;
}
Dass es nicht Thread-Save ist. Dass die Logik nicht an einer Stelle
konzentriert ist.
Außer, daß D eine andere Syntax benutzt, und der Callback-Funktion keinen
Namen gibt (und man bei diesem Funktionslayout nicht um eine globale
Variable herum kommt)?
Die Unterschiede sind fein.
Mir ging es darum, dem OP eine Frage zu beantworten.
Dir geht es scheinbar darum, auf einer Disput-Showbühne zu glänzen.
--
Helmut Leitner ***@hls.via.at
Graz, Austria www.hls-software.com
Bodo Thiesen
2003-07-06 02:20:57 UTC
Permalink
CallBackFunt_t compare;
switch (preferences->sort) {
case SORT_NAME: abc=compare_name; break;
case SORT_POINTS: abc=compage_points; break;
/* usw */
}
qsort(...,compare);
Das funktioniert natürlich nicht. Richtig würde es so aussehen:

CallBackFunt_t compare;

switch (preferences->sort) {
case SORT_NAME: compare=compare_name; break;
case SORT_POINTS: compare=compage_points; break;
/* usw */
}

qsort(...,compare);

Gruß, Bodo
--
MS Outlook Express?->[DE: http://piology.org/ILOVEYOU-Signature-FAQ.html]

@@@@@ GEGEN TCG aka. TCPA: @@@@@ [DE: http://www.againsttcpa.com]
Probleme mit Spam? [EN: http://www.spamhaus.org/globalremove.html]
Claus Reibenstein
2003-07-03 06:37:29 UTC
Permalink
Diese Funktion [...]
ruft mit jeder gefundenen Datei die Funktion f auf. Z. B.
¯
DirFindFileCall("C:\\TEST","*.c",test,DFFC_FILES|DFFC_RECURSE);
¯¯¯¯

Äh ... ;-)

SCNR. Claus
Bodo Thiesen
2003-07-04 03:12:12 UTC
Permalink
Post by Claus Reibenstein
Diese Funktion [...]
ruft mit jeder gefundenen Datei die Funktion f auf. Z. B.
¯
DirFindFileCall("C:\\TEST","*.c",test,DFFC_FILES|DFFC_RECURSE);
Äh ... ;-)
Nun ja, "Wer den Schaden hat ..."

Aber vielleicht ist ja test() auch so implementiert:

ER inline test(CH *dir,CH *fnam,FILEINFO *fb) {
return f(dir,fnam,fb);
}

Oder es wurde gar folgendes gemacht:

#define test f
Post by Claus Reibenstein
SCNR. Claus
dito. :-)

Gruß, Bodo
--
MS Outlook Express?->[DE: http://piology.org/ILOVEYOU-Signature-FAQ.html]

@@@@@ GEGEN TCG aka. TCPA: @@@@@ [DE: http://www.againsttcpa.com]
Probleme mit Spam? [EN: http://www.spamhaus.org/globalremove.html]
Bodo Thiesen
2003-07-02 22:14:40 UTC
Permalink
Claus Reibenstein <***@pop-hannover.de> wrote:

[Call-Back Funktionen]
Die Verwendung solcher Funktionen ist keine besondere Eigenart von C.
Das geht mit jeder anderen Programmiersprache auch.
Niet.

man Basic

Ok, es geht mit vielen, aber sicher nicht mit allen.

Gruß, Bodo
--
MS Outlook Express?->[DE: http://piology.org/ILOVEYOU-Signature-FAQ.html]

@@@@@ GEGEN TCG aka. TCPA: @@@@@ [DE: http://www.againsttcpa.com]
Probleme mit Spam? [EN: http://www.spamhaus.org/globalremove.html]
Mathias Grimmberger
2003-07-04 20:04:42 UTC
Permalink
Post by Bodo Thiesen
[Call-Back Funktionen]
Die Verwendung solcher Funktionen ist keine besondere Eigenart von C.
Das geht mit jeder anderen Programmiersprache auch.
Niet.
man Basic
Welches BASIC denn? :-)
Post by Bodo Thiesen
Ok, es geht mit vielen, aber sicher nicht mit allen.
Das gilt andersherum fuer die BASICS, es geht mit vielen nicht
aber sicher nicht mit allen nicht.


MGri
--
Mathias Grimmberger <***@zaphod.sax.de>
Eat flaming death, evil Micro$oft mongrels!
Bodo Thiesen
2003-07-05 00:18:05 UTC
Permalink
Post by Mathias Grimmberger
Post by Bodo Thiesen
[Call-Back Funktionen]
Die Verwendung solcher Funktionen ist keine besondere Eigenart von C.
Das geht mit jeder anderen Programmiersprache auch.
Niet.
man Basic
Welches BASIC denn? :-)
Konkrete Beispiele? QBASIC (MS-Doofs 5.00)
PowerBasic mehrere Versionen
C64 Basic (das originale, also ohne Erweiterungen - davon gibt es zuviele)
Post by Mathias Grimmberger
Post by Bodo Thiesen
Ok, es geht mit vielen, aber sicher nicht mit allen.
Das gilt andersherum fuer die BASICS, es geht mit vielen nicht
aber sicher nicht mit allen nicht.
Du hast aber unterstellt, das ginge mit allen ("mit *jeder*
anderen Programmiersprache").

Gruß, Bodo
--
MS Outlook Express?->[DE: http://piology.org/ILOVEYOU-Signature-FAQ.html]

@@@@@ GEGEN TCG aka. TCPA: @@@@@ [DE: http://www.againsttcpa.com]
Probleme mit Spam? [EN: http://www.spamhaus.org/globalremove.html]
Claus Reibenstein
2003-07-05 18:49:19 UTC
Permalink
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Post by Bodo Thiesen
Das geht mit jeder anderen Programmiersprache auch.
Du hast aber unterstellt, das ginge mit allen ("mit *jeder*
anderen Programmiersprache").
Du solltest besser auf die Absender achten :-)

Gruß. Claus
Mathias Grimmberger
2003-07-05 19:50:05 UTC
Permalink
Post by Bodo Thiesen
Post by Mathias Grimmberger
Post by Bodo Thiesen
[Call-Back Funktionen]
Die Verwendung solcher Funktionen ist keine besondere Eigenart von C.
Das geht mit jeder anderen Programmiersprache auch.
Niet.
man Basic
Welches BASIC denn? :-)
Konkrete Beispiele? QBASIC (MS-Doofs 5.00)
PowerBasic mehrere Versionen
C64 Basic (das originale, also ohne Erweiterungen - davon gibt es zuviele)
Fein, mit denen geht es nicht. Dafuer geht es vermutlich mit VB 6 und
sicher mit VB.NET.
Post by Bodo Thiesen
Post by Mathias Grimmberger
Post by Bodo Thiesen
Ok, es geht mit vielen, aber sicher nicht mit allen.
Das gilt andersherum fuer die BASICS, es geht mit vielen nicht
aber sicher nicht mit allen nicht.
Du hast aber unterstellt, das ginge mit allen ("mit *jeder*
anderen Programmiersprache").
<staun>Noe.</staun> Das war Claus Reibenstein.


MGri
--
Mathias Grimmberger <***@zaphod.sax.de>
Eat flaming death, evil Micro$oft mongrels!
Tuyen Do
2003-07-04 22:37:23 UTC
Permalink
Callback-funktionen werden z.B. in 2 unterschiedlichen Programme benutzt:

ich habe "prog1.exe" und "prog2.exe".... in Prog1 steht die Callbackfunktion
"cb", die eine Antwort von Prog2 erwartet.

Nun führe ich von Prog1 mein Prog2 aus und übergebe die Adresse von der
Funktion "cb" (Zeiger) an Prog2, damit kann Prog2 eine Antwort geben, indem
es "cb" aufruft.

--
MfG,
T. Do
Helmut Leitner
2003-07-05 07:09:49 UTC
Permalink
Post by dieter_regenberg
Hallo,
das hat sich hier aber irgenwie verselbstständigt.
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Nein ein solcher Zusammenhang besteht nicht.

Die qsort-Standardfunktion sortiert einen Array und ruft die
Callback-Funktion immer dann auf, wenn es zwei Elemente des
Arrays vergleichen will. In dieser Callback-Funktion ist sozusagen
das Know-how verpackt, wie man entscheidet was < oder > oder = ist.

Eine andere typische Callback-Funktion ist die "Window-Procedure" bei
der MS-Windows-Programmierung. Sie muss vom Programmierer beigesteuert
werden und wird vom Windows-System immer dann aufgerufen, wenn mit
einem Fenster irgendetwas passiert. Ein Parameter teilt das Ereignis
mit (z. B. WM_SIZE / es hat sich die Größe des Fensters verändert).
Der Programierer kann in dieser Callback-Funktion reagieren und so
wesentliche Eigenschaften des Fensters festlegen.

Im Grunde wird mit der Callback-Funktion ein Stückchen
Objektorientierung erzeugt. Es gibt modernere Sprachen, in denen
Objekte ihre Vergleichsoperationenen als Methoden mitbringen:
Object x,y;
if( x.cmp(y) ) ....
und wo seine Sortierung auf Callbacks verzichten kann:
Object x[100];
...
x.sort();
Die Callback-Funktion ist also vielfach ein Ersatz für die
Bindung von Funktionen an Objekte (OO Methoden).

Andererseits ist die Callback-Funktion aber so etwas wie ein
wiederkehrendes technisches Muster mit der Bedeutung:
- ein Funktionspointer wird übergeben zum Zweck die
referenzierte Funktion an anderer Stelle aufzurufen.
Nicht mehr und nicht weniger.

--
Helmut Leitner ***@hls.via.at
Graz, Austria www.hls-software.com
dieter_regenberg
2003-07-05 16:04:18 UTC
Permalink
Post by Helmut Leitner
Post by dieter_regenberg
Hallo,
das hat sich hier aber irgenwie verselbstständigt.
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Nein ein solcher Zusammenhang besteht nicht.
Die qsort-Standardfunktion sortiert einen Array und ruft die
Callback-Funktion immer dann auf, wenn es zwei Elemente des
Arrays vergleichen will. In dieser Callback-Funktion ist sozusagen
das Know-how verpackt, wie man entscheidet was < oder > oder = ist.
Hoffe nicht zu nerven, aber irgendwie verstehe ich das immer noch
nicht.

Nehmen wir mal das obige Beispiel,d.h. doch das die CallBack Funktion
z.B.
zwei Elemente vergleichen soll. Warum rufe ich die Funktion denn dann
nicht einfach über ihren Namen auf, wie ich das ja sonst auch machen
würde.
Wo ist denn der große Vorteil wenn ich sie über einen Zeiger aufrufe?

Gruss

Dieter
Kostka, Volkmar
2003-07-05 16:16:06 UTC
Permalink
Post by dieter_regenberg
Post by Helmut Leitner
Post by dieter_regenberg
Hallo,
das hat sich hier aber irgenwie verselbstständigt.
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Nein ein solcher Zusammenhang besteht nicht.
Die qsort-Standardfunktion sortiert einen Array und ruft die
Callback-Funktion immer dann auf, wenn es zwei Elemente des
Arrays vergleichen will. In dieser Callback-Funktion ist sozusagen
das Know-how verpackt, wie man entscheidet was < oder > oder = ist.
Hoffe nicht zu nerven, aber irgendwie verstehe ich das immer noch
nicht.
Nehmen wir mal das obige Beispiel,d.h. doch das die CallBack Funktion
z.B.
zwei Elemente vergleichen soll. Warum rufe ich die Funktion denn dann
nicht einfach über ihren Namen auf, wie ich das ja sonst auch machen
würde.
Wo ist denn der große Vorteil wenn ich sie über einen Zeiger aufrufe?
Callback-Funktionen werden dann verwendet, wenn der Kontext, in dem die
Funktion aufgerufen wird, nicht unter deiner Kontrolle liegt. Im Falle
von qsort ist die Funktion nicht unter deiner Kontrolle, da du die
Implementierung nicht kennst. qsort muss eine Entscheidung treffen, die
zur Zeit der Implementierung unbekannt war. Da qsort bereits "fertig"
ist, kann die Entscheidungsfunktion nicht direkt eingefuegt werden.
Daher wird an qsort der Zeiger einer Funktion uebergeben, die diese
Entscheidung treffen kann.

Diese Funktion muss fuer jede moegliche Kombination von zwei Elementen
aufgerufen werden, die qsort vergleichen will. Wie willst du das ausser-
halb des Kontextes von qsort machen?

MFG

Volkmar Kostka
Helmut Leitner
2003-07-05 20:39:02 UTC
Permalink
Post by dieter_regenberg
Post by Helmut Leitner
Post by dieter_regenberg
Hallo,
das hat sich hier aber irgenwie verselbstständigt.
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Nein ein solcher Zusammenhang besteht nicht.
Die qsort-Standardfunktion sortiert einen Array und ruft die
Callback-Funktion immer dann auf, wenn es zwei Elemente des
Arrays vergleichen will. In dieser Callback-Funktion ist sozusagen
das Know-how verpackt, wie man entscheidet was < oder > oder = ist.
Hoffe nicht zu nerven, aber irgendwie verstehe ich das immer noch
nicht.
Nehmen wir mal das obige Beispiel,d.h. doch das die CallBack Funktion
z.B.
zwei Elemente vergleichen soll. Warum rufe ich die Funktion denn dann
nicht einfach über ihren Namen auf, wie ich das ja sonst auch machen
würde.
Wo ist denn der große Vorteil wenn ich sie über einen Zeiger aufrufe?
Du rufst sie ja nicht einfach über einen Zeiger auf.

Ich glaube, am einfachsten geht's mit einem konkreten qsort-Beispiel
(ohne Garantie, dass da jedes Tüpfelchen stimmt):

Du hast eine Struktur

typedef struct ADRESSE {
char fnam[40];
char vnam[40];
chr strasse[40];
int plz;
chr ort[40];
} ADRESSE;

und eine Tabelle daraus, die entsprechende Daten enthalten soll:

#define ADRTABDIM 100
ADRESSE AdrTab[ADRTABDIM];

Jetzt willst du diese Adresse mal nach
- Familienname und
- Vorname
mal nach
- Postleitzahl und
- Straße
sortieren. Ich nehme mal an, das würde dich einigermaßen beschäftigen,
das zu realisieren.

Gottseidank gibt's qsort, das einem solcherlei abnehmen kann, aus der
Dokumentation findest du:

#include <stdlib.h>
void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const
void *));

also schreibst du zum Sortieren z. B.

qsort(AdrTab,ADRTABDIM,sizeof AdrTab[0],AdrTabSortFnamVnamCallback);

an anderer Stelle

qsort(AdrTab,ADRTABDIM,sizeof AdrTab[0],AdrTabSortPlzOrtCallback);

d. h. du sagt

- Ort der Tabelle
- Anzahl der Elemente
- Größe des einzelnen Element
- Entscheidung welches größer ist

Natürlich musst du dann noch die Callback-Funktionen schreiben, wobei deine
Funktion von qsort vielfach aufgerufen wird und a und b Zeiger sind, die zu
beliebigen Elementen deiner Tabelle zeigen.

int AdrTabSortFnamVnamCallback(const void *x,const void *y)
{
ADRTAB *ax=(ADRTAB *)x;
ADRTAB *ay=(ADRTAB *)y;
int ret;

ret=strcmp(ax->fnam,ay->fnam);
if(ret==0) {
ret=strcmp(ax->vnam,ay->vnam);
}
return ret;
}

int AdrTabSortPlzOrtCallback(const void *x,const void *y)
{
ADRTAB *ax=(ADRTAB *)x;
ADRTAB *ay=(ADRTAB *)y;
int ret;

ret=(ax->plz - ay->plz);
if(ret==0) {
ret=strcmp(ax->strasse,ay->strasse);
}
return ret;
}

Die Funktion qsort arbeitet nach dem bekannten Quicksort-Algorithmus
und du müsstest dich schon strecken, um das selbst besser hinzukriegen:

<http://www.wikiservice.at/dse/wiki.cgi?QuickSort>

So schreibst du nur die Callback-Funktionen und scherst sich sonst um nichts.

Wolltest die die Callback-Funktionen selbst aufrufen
(deine Frage: "Warum nicht?") -
dann müsstest du den Sortieralgorithmus selber schreiben, was ja nicht der Sinn
der ganzen Sache ist.

Ziele sind: Wiederverwendung, Arbeitsersparnis, Produktivität, fertige
Funktionen mit möglichst wenig Aufwand Wiederverwenden, siehe:

<http://www.wikiservice.at/dse/wiki.cgi?EKEIDP>

--
Helmut Leitner ***@hls.via.at
Graz, Austria www.hls-software.com
dieter_regenberg
2003-07-06 11:38:30 UTC
Permalink
Post by Helmut Leitner
Post by dieter_regenberg
Post by Helmut Leitner
Post by dieter_regenberg
Hallo,
das hat sich hier aber irgenwie verselbstständigt.
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Nein ein solcher Zusammenhang besteht nicht.
Die qsort-Standardfunktion sortiert einen Array und ruft die
Callback-Funktion immer dann auf, wenn es zwei Elemente des
Arrays vergleichen will. In dieser Callback-Funktion ist sozusagen
das Know-how verpackt, wie man entscheidet was < oder > oder = ist.
Hoffe nicht zu nerven, aber irgendwie verstehe ich das immer noch
nicht.
Nehmen wir mal das obige Beispiel,d.h. doch das die CallBack Funktion
z.B.
zwei Elemente vergleichen soll. Warum rufe ich die Funktion denn dann
nicht einfach über ihren Namen auf, wie ich das ja sonst auch machen
würde.
Wo ist denn der große Vorteil wenn ich sie über einen Zeiger aufrufe?
Du rufst sie ja nicht einfach über einen Zeiger auf.
Ich glaube, am einfachsten geht's mit einem konkreten qsort-Beispiel
Du hast eine Struktur
typedef struct ADRESSE {
char fnam[40];
char vnam[40];
chr strasse[40];
int plz;
chr ort[40];
} ADRESSE;
#define ADRTABDIM 100
ADRESSE AdrTab[ADRTABDIM];
Jetzt willst du diese Adresse mal nach
- Familienname und
- Vorname
mal nach
- Postleitzahl und
- Straße
sortieren. Ich nehme mal an, das würde dich einigermaßen beschäftigen,
das zu realisieren.
Gottseidank gibt's qsort, das einem solcherlei abnehmen kann, aus der
#include <stdlib.h>
void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const
void *));
also schreibst du zum Sortieren z. B.
qsort(AdrTab,ADRTABDIM,sizeof AdrTab[0],AdrTabSortFnamVnamCallback);
an anderer Stelle
qsort(AdrTab,ADRTABDIM,sizeof AdrTab[0],AdrTabSortPlzOrtCallback);
d. h. du sagt
- Ort der Tabelle
- Anzahl der Elemente
- Größe des einzelnen Element
- Entscheidung welches größer ist
Natürlich musst du dann noch die Callback-Funktionen schreiben, wobei deine
Funktion von qsort vielfach aufgerufen wird und a und b Zeiger sind, die zu
beliebigen Elementen deiner Tabelle zeigen.
int AdrTabSortFnamVnamCallback(const void *x,const void *y)
{
ADRTAB *ax=(ADRTAB *)x;
ADRTAB *ay=(ADRTAB *)y;
int ret;
ret=strcmp(ax->fnam,ay->fnam);
if(ret==0) {
ret=strcmp(ax->vnam,ay->vnam);
}
return ret;
}
int AdrTabSortPlzOrtCallback(const void *x,const void *y)
{
ADRTAB *ax=(ADRTAB *)x;
ADRTAB *ay=(ADRTAB *)y;
int ret;
ret=(ax->plz - ay->plz);
if(ret==0) {
ret=strcmp(ax->strasse,ay->strasse);
}
return ret;
}
Die Funktion qsort arbeitet nach dem bekannten Quicksort-Algorithmus
<http://www.wikiservice.at/dse/wiki.cgi?QuickSort>
So schreibst du nur die Callback-Funktionen und scherst sich sonst um nichts.
Wolltest die die Callback-Funktionen selbst aufrufen
(deine Frage: "Warum nicht?") -
dann müsstest du den Sortieralgorithmus selber schreiben, was ja nicht der Sinn
der ganzen Sache ist.
Ziele sind: Wiederverwendung, Arbeitsersparnis, Produktivität, fertige
<http://www.wikiservice.at/dse/wiki.cgi?EKEIDP>
Hallo Helmut,

vielen Dank für Deine tolle Erklärung.

Habe vertstanden.

Bin immer noch auf der Suche nach einem Buch,
wo man soetwas nachlesen kann. Also wo weniger
die eigentliche Syntax der Sprache sondern die
Anwendung beschrieben wird.

Vieleicht solltest Du mal so ein Buch schreiben,
es ist nicht jedem gegeben solch einen Sachverhalt
einfach und klar darzustellen.

MFG

Dieter
Helmut Schellong
2003-07-05 16:23:39 UTC
Permalink
Post by dieter_regenberg
Hallo,
das hat sich hier aber irgenwie verselbstständigt.
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Nein.

Callback heißt ja: "rufe zurück".

Beispielsweise ich rufe per Modem eine industrielle
Kontrolleinheit an und lasse es 5..10mal klingeln.
Die Einheit ruft mich daraufhin an und meldet den Status.

Es gibt bei WIndows-Programmen CallBack-Funktionen, die vom
Windows-System aufgerufen werden, um z.B. Ereignisse mitzuteilen.

Eine Callback-Funktion ist einfach eine Funktion, deren Adresse
irgendwo hin gegeben wird und die dann von dort aufgerufen wird.
Analog zu meiner Telefonnummer, die das Modem anruft.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.de ***@schellong.com
www.schellong.de www.schellong.biz ***@t-online.de
http://www.wikiservice.at/dse/wiki.cgi?FreeBSD
Holger Suhr
2003-07-07 06:48:22 UTC
Permalink
Post by dieter_regenberg
Eine CallBack Funktion ist eine Funktion, welche widerum eine
weitere Funktion (über einen Zeiger) aufruft. Was ich noch
nicht verstanden habe ist, wann denn diese zweite Funktion
aufgerufen wird (wenn die erste TRUE zurück liefert?
Das hast Du - glaube ich - mißverstanden.
Die Callback-Funktion ist diejenige, die durch eine von Deinem
Programm 'gecallte' Funktion wiederum aufgerufen wird.

In der Praxis sind es oft z.B. Funktionen, die einen Standard
Algorithmus zu 90% erledigen können, (wie z.B. qsort()), die
eine Callback-Funktion benötigen.

Qsort() ist eine fertige Funktion, die eben das Sortieren
eines Vektors zu 90% erledigen kann. Für die letzten 10%
musst Du eine Callback-Funktion zur Verfügung stellen,
die Funktion, die entscheiden kann, welches von 2 Elementen
des Vektors das größere ist.
Diese Funktion wird dann von qsort() (mehrfach, häufig)
aufgerufen.

Da Du qsort aufgerufen hast, und qsort nun wiederum Dich
aufruft, sagt man Callback.

Gruß Holger
Ingo Oeser
2003-08-04 03:00:50 UTC
Permalink
Post by dieter_regenberg
kann mir mal Jemand die genaue Funktionsweise von CallBack Funktionen
erklären.
Welchen Vorteil bzw. Nachteil hat die Verwendung solcher Funktinen unter C?
Eine CallBack-Funktion ist eine Moeglichkeit, beliebiges, undefiniertes
Verhalten an der Stelle, an der sie aufgerufen wird unterzubringen.

Deswegen wird auch das von der CallBack-Funktion erwartete Verhalten
immer so genau definiert.

Sowas wird meistens genommen, um OOP oder generische Programmierung in C
zu realisieren.

Wenn man sowas haeufig braucht, dann verwendet man meist gerade die
falsche Sprache ;-)

Grusz
Ingo
--
Marketing ist die Kunst, Leuten Sachen zu verkaufen, die sie
nicht brauchen, mit Geld, was sie nicht haben, um Leute zu
beeindrucken, die sie nicht moegen.
Loading...