Forum: Compiler & IDEs C Funktionspointer auf sich selbst


von   jgdo (Gast)


Lesenswert?

Hallo,

ich möchte eine Funktion erstellen, die einen Zeiger auf eine Funktion 
mit gleicher Signatur wie die Funktion selbst zurückgibt. Also so, dass 
man die Funktion mittels

f(bla)(blub)(foo)...

beliebig oft direkt nacheinander aufrufen kann. Ist das in C(++) möglich 
und wenn ja, wie hat der Funktionskopf auszusehen?

- jgdo -

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

parse error.

von Karl H. (kbuchegg)


Lesenswert?


von Klaus W. (mfgkw)


Lesenswert?

Vielleicht mit einem Funktionsobjekt:
1
#include <iostream>
2
3
class MyFO
4
{
5
public:
6
    MyFO &operator()( int a )
7
    {
8
        std::cout << "operator()( int a = " << a << " )" << std::endl;
9
        return *this;
10
    }
11
};
12
13
int main( int nargs, char **args )
14
{
15
    MyFO     myFO;
16
17
    myFO( 5 )( 4 )( 42 );
18
}

Das ergibt:
1
F:\kw>cl /EHsc t.cpp
2
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
3
Copyright (C) Microsoft Corporation.  All rights reserved.
4
5
t.cpp
6
Microsoft (R) Incremental Linker Version 9.00.30729.01
7
Copyright (C) Microsoft Corporation.  All rights reserved.
8
9
/out:t.exe
10
t.obj
11
12
F:\kw>t
13
operator()( int a = 5 )
14
operator()( int a = 4 )
15
operator()( int a = 42 )

Von wegen parse error ... :-)

von Simon K. (simon) Benutzerseite


Lesenswert?

+ 1 auf Abgefahrenheit :-D

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Klaus Wachtler schrieb:
> Von wegen parse error ... :-)

Der parse error war schlichtweg in meinem Kopf: ich habe einfach nicht 
verstanden, was er wollte und wozu das Ganze gut ist. Letzteres weiß ich 
immer noch nicht.

von Klaus W. (mfgkw)


Lesenswert?

Frank M. schrieb:
> Letzteres weiß ich immer noch nicht.

ich auch nicht, aber es läuft doch.

von Klaus W. (mfgkw)


Lesenswert?

Sein Problem ist in C in der Tat nicht trivial bzw. vielleicht gar nicht 
lösbar, weil man den Typ "Zeiger auf eine Funktion..." in derselben 
Typdefinition noch nicht als Rückgabe der Funktion verwenden kann.

Wie will man dann eine Funktion definieren, die einen Zeiger auf sich 
selbst liefert? So eine leere forward-Deklaration wie bei structs gibt 
es für Funktionen ja nicht.

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


Lesenswert?

Klaus Wachtler schrieb:
> Von wegen parse error ... :-)

Thema verfehlt.  Im Subject steht "C", nicht "C++".

Aber pervers ist dein Zeugs da schon. ;-)

von   jgdo (Gast)


Lesenswert?

Danke für die Antworten Leute.

@Karl Heinz Buchegger
Das ist eine Möglichkeit, aber ich wollte die Casts eben vermeiden. 
Schade dass es direkt nicht geht.

@Klaus Wachtler
Ist eine Klasse und keine Funktion.

@alle
mir gings eher um das Prinzip, eine echte Anwendung dafür habe ich 
nicht. Ich habe nur eine Funktion, die mehrmals nacheinander mit 
verschiedenen Parametern aufgerufen wird und ich wollte mal einfach 
etwas Tipparbeit sparen ;)

von Kan a. (Firma: Basta) (kanasta)


Lesenswert?

void * Func(...) {
...
return &Func;
}


so vielleicht?

von Kan a. (Firma: Basta) (kanasta)


Lesenswert?

int res;

void *Func(int p1) {
  res += p1;
  return &Func;
}

int main(void) {
  res = 0;

  int (*p)(int) = Func(5);
  (*p)(10);

  printf("res=%d", res);
}


Also irgendwie krieg ich das Func(x)(y) nicht hin. Weiß jemand anderes 
weiter?

von Karl H. (kbuchegg)


Lesenswert?

Kan asta schrieb:
> int res;
>
> void *Func(int p1) {
>   res += p1;
>   return &Func;
> }

Du hast die Problemstellung noch nicht verstanden

> Also irgendwie krieg ich das Func(x)(y) nicht hin. Weiß jemand anderes
> weiter?

Sieh dir den FAQ Link von weiter oben an. Da sind 2 Lösungsmöglichkeiten 
gegeben. Beide nicht besonders schön.
Das Problem, wie schon weiter oben vermerkt, besteht darin, dass es 
sowas wie eine 'Forward-Deklaration' für Funktionspointer nicht gibt. 
Die würde man aber brauchen, damit man einen Funktionspointer machen 
kann, auf eine Funktion die genau diesen Funktionspointer-Typ liefert.

von Klaus W. (mfgkw)


Lesenswert?

  jgdo schrieb:
> @Klaus Wachtler
> Ist eine Klasse und keine Funktion.

Manchen kann man es nie recht machen...

Dann halt als Funktion:
1
#include <iostream>
2
3
class MyFO
4
{
5
private:
6
    MyFO (*m_f)( int a );
7
8
public:
9
    MyFO( MyFO (*f)( int a ) )
10
        : m_f(f)
11
    {}
12
13
    MyFO operator()( int a )
14
    {
15
        return m_f( a );
16
    }
17
};
18
19
MyFO f( int a )
20
{
21
    std::cout << "operator()( int a = " << a << " )" << std::endl;
22
    return MyFO( f );
23
}
24
25
int main( int nargs, char **args )
26
{
27
    f( 5 )( 4 )( 42 );
28
}

Gleiche Ausgabe wie oben.

von Klaus W. (mfgkw)


Lesenswert?

Jörg Wunsch schrieb:
> Thema verfehlt.  Im Subject steht "C", nicht "C++".

nee, Überschrift falsch!
Im OP steht "...C(++)..."

von max (Gast)


Lesenswert?

Hm, was spricht dagegen die Parameter in ein Array zu packen und über 
dieses zu Iterieren? Ob es nun besser ist, das Array als ganzes an die 
Funktion zu übergeben oder jeden Parameter einzeln ist dann wieder ein 
anderes Thema. (ersteres ist besser lesbar und sollte auch in 
schnellerem Code resultieren, letzteres ist universeller)

von Karl H. (kbuchegg)


Lesenswert?

max schrieb:
> Hm, was spricht dagegen die Parameter in ein Array zu packen und über
> dieses zu Iterieren?


Na, ja. Das ganze war ja bis jetzt nur eine Spielerei :-)

so richtig geil wird das ganze dann, wenn eine Funktion (abhängig vom 
Parameter) nicht sich selbst zurückgibt, sondern einen Pointer auf eine 
ganz andere Funktion. Man kann da dann ein ganzes Netzwerk von 
Funktionsaufrufen hinter der harmlos anmutenden Syntax

   foo(4)(5)(6)(8);

(oder auch

    do {
      f = f(Werte[i++]);
    } while( f );
)

aufbauen, das kein Mensch mehr ohne 5 Liter Kaffee und eine Großpackung 
Baldrian durchschaut :-) Sowas nennt man dann "aktive 
Arbeitsplatzsicherung".

von max (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> aufbauen, das kein Mensch mehr ohne 5 Liter Kaffee und eine Großpackung
> Baldrian durchschaut :-) Sowas nennt man dann "aktive
> Arbeitsplatzsicherung".

und der Sieg beim IOCCC sicher ist :)

von Ben j. (scarab)


Lesenswert?

Karl Heinz Buchegger schrieb:
> aufbauen, das kein Mensch mehr ohne 5 Liter Kaffee und eine Großpackung
> Baldrian durchschaut :-) Sowas nennt man dann "aktive
> Arbeitsplatzsicherung".

You made my day :D

von Dani Zwirner (Gast)


Lesenswert?

So gehts:
1
#include "stdio.h"
2
3
typedef int (*fp)(int);
4
5
fp f(int i)
6
{
7
  printf("i=%i\n", i);
8
  return (fp)f;
9
}
10
11
int main(int argc, char ** argv)
12
{
13
  f(1)(2);
14
  return 1;
15
}

aber leider nur mit zweifachem Aufruf. Beim dreifachen Aufruf
1
f(1)(2)(3);
meint der gcc error: called object ‘f(1)(2)’ is not a function

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Ihr spinnt :-)))

von Ben j. (scarab)


Lesenswert?

kann man nicht einfach mit einem Makro einen Zeiger auf ein Array von 
Parametern übergeben und dann die Funktion einfach mehrmals aufrufen?

sowas wie
1
#define foo(var) foo_fctn({ (var) })
2
3
//oder falls das nicht geht:
4
5
#define foo(var)                \
6
int array[]={ (var) , 0x7FFF }; \
7
foo_fctn(array);
8
9
int foo_fctn(int * array)
10
{
11
    int i=0;
12
    while( array[i] != 0x7FFF )
13
    {
14
       res += foo_nocheine( array[i] );
15
       i++;
16
    }
17
    return res;
18
}
19
20
var = foo(1);
21
var = foo(1,2);
22
var = foo(1,2,3);
23
var = foo(1,2,3,4);

(alles nicht getesten, hab auf meinem Laptop keine IDE ^^)

EDIT: nagut, das array wird bei mehrfacher Verwendung des Makros im 
selben Gültigkeitsbereich Probleme machen aber das Prinzip sollte ja 
ersichtlich sein oder?

EDIT2: werden die Kommas Probleme machen? vielleicht Klammern 
"Übergeben" und temporär Klammern als Komma definieren? xD (falls die 
erste Variante nicht funktioniert)

von Mark B. (markbrandis)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Sowas nennt man dann "aktive Arbeitsplatzsicherung".

In richtig guten Firmen kriegen die Leute eine Abmahnung, die solchen 
Code verfassen. ;-)

von Klaus W. (mfgkw)


Lesenswert?

Wieso?
Das ist nur eine andere Form eines Zustandsautomats - für den wird man 
auch nicht automatisch abgemahnt.

von Stephan (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Sowas nennt man dann "aktive
> Arbeitsplatzsicherung".

Nope, das nennt man Funktionale Programmierung und ist absolut 
faszinierend, wenn man sich für theoretische Informatik interessiert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Dani Zwirner schrieb:
> So gehts:
> [...]
> aber leider nur mit zweifachem Aufruf. Beim dreifachen Aufruf
>
1
> f(1)(2)(3);
2
>
> meint der gcc error: called object ‘f(1)(2)’ is not a function

  ((fp) (f(1)(2)))(3);

bzw.

  ((fp) ((fp) (f(1)(2)))(3))(4);

usw.

funktionieren. Das sieht aber nicht mehr so schön aus ;-)

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> so richtig geil wird das ganze dann, wenn eine Funktion (abhängig vom
> Parameter) nicht sich selbst zurückgibt, sondern einen Pointer auf eine
> ganz andere Funktion [..] das kein Mensch mehr ohne 5 Liter Kaffee und
> eine Großpackung Baldrian durchschaut :-)
> Sowas nennt man dann "aktive Arbeitsplatzsicherung"
Oder Method Chaining/Fluent Interface:
http://en.wikipedia.org/wiki/Method_chaining
http://en.wikipedia.org/wiki/Fluent_interface
Ich nutze das ab und an mal konnte mich aber bisher noch nicht im großen 
Stil dafür erwärmen...

Wird zwar immer im Zusammenhang mit OO genannt, aber wieso sollte man 
das nicht auch mal in C umsetzen? Der arme Compiler...

von Mark B. (markbrandis)


Lesenswert?

Klaus Wachtler schrieb:
> Wieso?
> Das ist nur eine andere Form eines Zustandsautomats - für den wird man
> auch nicht automatisch abgemahnt.

Normalerweise sollte es in einer Firma Richtlinien für die Codierung 
geben. Wenn die Firma Wert auf Qualität legt (das tut freilich nicht 
jede), dann sorgt sie auch dafür, dass diese Richtlinien eingehalten 
werden. Solche Tools wie z.B. MISRA C++ Code Checker mögen in der Regel 
"arbeitsplatzsichernden Code" nicht besonders :-)

von Yalu X. (yalu) (Moderator)


Lesenswert?

jgdo schrieb:
> ich möchte eine Funktion erstellen, die einen Zeiger auf eine Funktion
> mit gleicher Signatur wie die Funktion selbst zurückgibt.

In Sprachen mit dynamischer Typisierung (z.B. Python) ist das kein
Problem:
1
def f(x):
2
  print('f called with', x)
3
  return f
4
5
f(1)(2)(3)(4)

liefert
1
f called with 1
2
f called with 2
3
f called with 3
4
f called with 4

Viele Sprachen mit statischer Typisierung scheinen aber Probleme zu
haben, den Typ dieser Funktion compiler-intern darzustellen. Auch in
Haskell, wo man das Ausdenken der Funktionssignaturen i.Allg. dem
Compiler überlassen und ganz lapidar
1
f x = f

schreiben kann, meckert der Compiler:
1
    Occurs check: cannot construct the infinite type: t1 = t0 -> t1
2
    In the expression: f
3
    In an equation for `f': f x = f

Das ist dort aber kein großes Problem, da dieses Konstrukt sowieso nur
für seiteneffektbehaftete Funktionen von Nutzen ist, die es in Haskell
gar nicht gibt.

Läubi .. schrieb:
> Oder Method Chaining/Fluent Interface:

Auch ganz interessant in diesem Zusammenhang:

  http://en.wikipedia.org/wiki/Continuation-passing_style

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.