Forum: Compiler & IDEs Warum Zeiger auf Funktion?


von Frager (Gast)


Lesenswert?

Hi,
kann jemanden mir sagen warum ist Zeiger auf Funktion überhaupt 
verwendet?
was ist das Ziel? kann der Inhalt von diesem  Zeiger auslesen?
wenn ich eine Funktion deklariere, die als Argument ein Zeiger auf 
Funktion hat. Wie wird überhaupt die Funtion aufgerufen? Was versteckt 
sich in diesem Argument?

von Udo S. (urschmitt)


Lesenswert?

Einfachstes Beispiel:
Du hast eine generische Sortierfunktion.
Woher weiß jetzt diese Sortierfunktion wie es bewerten soll welches von 
2 Objekten in der Reihenfolge zuerst kommt.
Du übergibst der Sortierfunktion einfach einen Zeiger auf eine 
Vergleichsfunktion mit 2 'void' zeigern die auf die zu vergleichenden 
Objekte zeigen. Die Funktion muss dann je nachdem welches Objekt 
'größer' ist -1, 0 oder 1 zurückliefern.
Schau dir qsort() an.

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


Lesenswert?

Frager schrieb:
> kann jemanden mir sagen warum ist Zeiger auf Funktion überhaupt
> verwendet?

Dann, wenn man erst zur Laufzeit (in Abhängigkeit von anderen Daten)
festlegen möchte, welche konkrete Funktion dann später aufgerufen
werden soll.

von Karl H. (kbuchegg)


Lesenswert?

Frager schrieb:
> Hi,
> kann jemanden mir sagen warum ist Zeiger auf Funktion überhaupt
> verwendet?
> was ist das Ziel?


Ein Funktion aufzurufen, die der Aufrufer nicht persönlich kennen muss, 
sondern die ihm wer anderer vorgibt.

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


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ein Funktion aufzurufen, die der Aufrufer nicht persönlich kennen muss,
> sondern die ihm wer anderer vorgibt.

Völlig falsch. Die Funktion soll variabel sein.

von Karl H. (kbuchegg)


Lesenswert?

Kan asta schrieb:
> Karl Heinz Buchegger schrieb:
>> Ein Funktion aufzurufen, die der Aufrufer nicht persönlich kennen muss,
>> sondern die ihm wer anderer vorgibt.
>
> Völlig falsch. Die Funktion soll variabel sein.

Und wie beißt sich das jetzt mit dem was ich gesagt habe?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Hier als Beispiel ein Auszug aus meinem Kommandointerpreter für µC 
(gekürzt):
1
// List of Shell internal Commands and Functions
2
int (*pShellCmdFunc[])(int argc, char **argv) = 
3
{ 
4
  Shell_Help, 
5
  Shell_Version,
6
  0
7
};
8
9
char *pShellCmdText[] = 
10
{ 
11
  "help",
12
  "ver",
13
  0
14
};
15
16
17
/**
18
* \author Th.dB.
19
* \param (char **argv)
20
* \return int (*)(int argc, char **argv)
21
* \brief Translates a command into a function pointer to the command
22
*/
23
int (*TranslateCommand(char **argv))(int argc, char **argv)
24
{
25
  int i=0;
26
  int tmp=0;
27
  
28
  tmp = strlen(argv[0]);
29
  do {    
30
    if(!(memcmp(argv[0], pShellCmdText[i], tmp+1 )) ) return(pShellCmdFunc[i]);     //cmd found
31
  } while(*pShellCmdText[i++]);
32
  
33
  return(0);
34
}
35
36
/**
37
* \author Th.dB
38
* \param void
39
* \return void
40
* \brief This is the main command-shell. Typed commands are executed from here
41
* \see "help"-Command
42
*/
43
__task void CommandShell(void)
44
{
45
  unsigned int retValue=0;     // 0: everything ok, else something is to be done ;-)
46
  int (*pCommand)(int argc, char **argv) = 0;
47
  
48
  while(1) {
49
    os_evt_wait_or (SHELL_NEW_CMD_READY, 0xffff);     // set task to sleep until a new command comes in
50
    
51
    if(*argvShell[0]) {
52
      pCommand = TranslateCommand(argvShell);
53
      if(pCommand) retValue = pCommand(argcShell, argvShell);
54
      else { // prints for example:  Unknown command: "heeeeelp"   ;-)
55
        thprintf("\n-thsh: %s: command not found", argvShell[0]);
56
        retValue = SHELL_RET_FAILURE;
57
      }
58
      
59
      if(retValue == SHELL_RET_LOGOUT) continue;      // go to os_evt_wait on logout
60
      
61
      ReleaseStdout();
62
      if(retValue) {
63
        ShellFuncFailure(retValue);
64
       
65
        PrintOk(retValue);
66
        thprintf("\n");
67
      }
68
    }        
69
    prompt(PROMPT_NORMAL);
70
  }
71
}
72
73
int Shell_Version(int argc, char **argv)
74
{
75
  thprintf("\nthsh V%s\n", SHELL_VER);
76
  return(SHELL_RET_NORMAL);
77
}


Oder hier:
1
void TakeStdin(void (*pfunc)(int c)) {
2
  stdinRedirect = pfunc;  
3
}
4
5
void SetStdinStandardHandler(void (*pfunc)(int c)) {
6
  stdinStandardHandler = pfunc;
7
}
8
9
void ReleaseStdin(void) {
10
  stdinRedirect = stdinStandardHandler;
11
}

von Frager (Gast)


Lesenswert?

Sorry,
Ich habe schon die Frage hier gestellt aber ohne Erfolg.
ich möchte einen Zeiger auf eine Funktion, der mir bei Sortierung eines 
Arrays helfen kann. D.h ob ich eine aufsteigende Sortierung oder 
absteigerung Sortierung mache.
Die Sortierung selbst ist kein Problem aber ich möchte nur diese mit 
einem Zeiger auf Funktion machen. Um zu lernen wie es funktioniert.
1) wenn pArray[0] > pArray[1]-> absteigend
2) wenn pArray[0] < pArray[1]-> aufsteigend

3)Nach meiner Meinung nach, wenn ich die Funktion vBubblesort 
aufrufe,dann soll Parameter 1 oder 0 sein
Im debbuger ich sehe nichts interessant.Ich bekomme sogar 2 verschiedene 
Adresse von pBubble beim Auruf von (*pBubble)(cArray) und  vBubblesort.

uint8_t (*pBubble)(char *pArray);//Pointer of function
uint8_t u8ChoiceBubble(char *pArray);//
void vBubblesort(uint8_t(*pBubble)(char *pArray),char *pArray, uint8_t 
u8length);
int main()
{

 pBubble = &u8ChoiceBubble;
 (*pBubble)(cArray);
 vBubblesort(u8ChoiceBubble,cArray, u8LencArray);

// u8InitDirection=u8ChoiceBubble(cArray);

}

uint8_t u8ChoiceBubble(char *pArray)
       {
          if(pArray[0] <  pArray[1])
          {

            return 1;
          }
        else
          {

           return 0;
          }
       }

void vBubblesort(uint8_t(*pBubble)(char *pArray),char *pArray, uint8_t 
u8length)

     {

    if(pBubble==1)
    {

    }
    if(pBubble==0)
    {

    }
     }

von Random .. (thorstendb) Benutzerseite


Lesenswert?

[c ] und [/c ] sind sehr hilfreich in diesem Forum. War mal so frei, das 
ganze lesbar zu gestalten:
1
uint8_t (*pBubble)(char *pArray);//Pointer of function
2
uint8_t u8ChoiceBubble(char *pArray);
3
4
void vBubblesort(uint8_t(*pBubble)(char *pArray),char *pArray, uint8_t u8length);
5
6
int main()
7
{
8
 pBubble = &u8ChoiceBubble;
9
 (*pBubble)(cArray);
10
 vBubblesort(u8ChoiceBubble,cArray, u8LencArray);
11
12
// u8InitDirection=u8ChoiceBubble(cArray);
13
}
14
15
uint8_t u8ChoiceBubble(char *pArray)
16
{
17
  if(pArray[0] <  pArray[1]) {
18
    return 1;
19
  }
20
  else {
21
    return 0;
22
  }
23
}
24
25
void vBubblesort(uint8_t(*pBubble)(char *pArray),char *pArray, uint8_t u8length)
26
{
27
  if(pBubble==1) {
28
  }
29
  if(pBubble==0) {
30
  }
31
}

Wenn ich mir das nun so anschaue ... Die untere fkt macht irgendwie 
keinen Sinn.
funcPtr==0 ==> ungültig. Ok.
Aber funcPtr==1 ==> ????

von Karl H. (kbuchegg)


Lesenswert?

Frager schrieb:
> Sorry,
> Ich habe schon die Frage hier gestellt aber ohne Erfolg.

Erinnere mich.
Du hast viele Antworten bekommen. Nur leider hast du sie nicht 
verstanden.
Die erste (und oberste) Frage ist.

Wozu brauchst du hier einen Zeiger auf eine Funktion?


> Die Sortierung selbst ist kein Problem aber ich möchte nur diese mit
> einem Zeiger auf Funktion machen. Um zu lernen wie es funktioniert.
> 1) wenn pArray[0] > pArray[1]-> absteigend
> 2) wenn pArray[0] < pArray[1]-> aufsteigend

Geh von deinem ursprünglichen Verfahren aus

  sorted = false;
  while( !sorted ) {
    sorted = true;

    for( i = 0; i < arraySize - 1; i++ ) {
      if( array[i] > array[i+1] ) {
        swap( array[i], array[i+1] );
        sorted = false;
      }
    }
  }

Dann gehst du her und verschiebst den Vergleich erst mal in eine 
Funktion

  sorted = false;
  while( !sorted ) {
    sorted = true;

    for( i = 0; i < arraySize - 1; i++ ) {
      if( sortOrder( array[i] > array[i+1] ) )
        swap( array[i], array[i+1] );
        sorted = false;
      }
    }
  }

und anstelle einer fixen Funktion sortOrder tritt dann ein 
Funktionspointer


> 3)Nach meiner Meinung nach, wenn ich die Funktion vBubblesort
> aufrufe,dann soll Parameter 1 oder 0 sein

Dann bringt dir das ganze nichts.
Denn dann braucht die Funktion keinen Funktionspointer.


> void vBubblesort(uint8_t(*pBubble)(char *pArray),
>                  char *pArray, uint8_t u8length)
> {
>   if(pBubble==1) {
>   }
>   if(pBubble==0) {
>   }
> }
>
> Wenn ich mir das nun so anschaue ... Die untere
> fkt macht irgendwie keinen Sinn.

Genau. Der Funktionspointer ist an dieser Stelle völlig sinnlos. Wenn du 
der Funktion sowieso mitgeben willst, ob sie aufsteigend oder absteigend 
zu sortieren hat, dann brauchst du auch keinen Funktionspointer. Ein 
normaler uint8_t würde es auch tun.

void vBubblesort(uint8_t ascending, char *pArray, uint8_t u8length)
{
  if( ascending )
    vBubbleSortAscending( pArray, length );
  else
    vBubbleSortDescending( pArray, length );
}

und dazu 2 Sortierroutinen von denen die eine aufsteiegend und die 
andere absteigend sortiert.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Das schaut weitaus sinnvoller aus:
1
void vBubblesort(uint8_t(*pBubble)(char *pArray), char *pArray, uint8_t u8length)
2
{
3
  uint8_t ret;
4
5
  if(!pBubble) return;
6
7
  ret = pBubble(pArray, u8length);
8
}
Ausserdem: Benutze besser Quicksort, it's really quick! Das blubbert 
nicht so lange :-)

von Frager (Gast)


Lesenswert?

was ist:

while( !sorted )

von Klaus W. (mfgkw)


Lesenswert?

Frager schrieb:
> while( !sorted )

Das kommt aus dem Indianischen und heißt etwa "lies mal endlich ein 
C-Buch"

von Karl H. (kbuchegg)


Lesenswert?

Frager schrieb:
> was ist:
>
> while( !sorted )

Lies es so wie es da steht. ! ist in C ein "nicht"

Das steht also:  Solange (while)  nicht (!)  sortiert (sorted)

Also: Die übliche C Schreibweise für

  while( sorted == FALSE )

oder auch

  while( sorted != TRUE )

oder eben

  while( !sorted )


(wobei sorted logischerweise eine Variable ist, die boolschen Character 
hat, also nur TRUE oder FALSE sein kann)


Edit: Aber ich merke gerade, dass ich da bei dem Codestück nicht 
besonders gut auf diesen Teilaspekt geachtet habe. Da sind ein paar 
Fehler drinnen (die nichts mit dem Ersatz durch einen Funktionspointer 
zu tun haben). Ich hab sie trotzdem korrigiert.

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> (wobei sorted logischerweise eine Variable ist, die boolschen Character
> hat, also nur TRUE oder FALSE sein kann)

was nicht so sein muss, in C kann es jede art von variable sein - sie 
muss nur auf 0 vergleichbar sein.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> Frager schrieb:
>> while( !sorted )
>
> Das kommt aus dem Indianischen und heißt etwa "lies mal endlich ein
> C-Buch"

Da hat der Klaus leider recht.

Wozu wirfst du mit Funktionspoitner um dich, wenn du an den Grundlagen 
schon Schwierigkeiten hast.
Erledige doch erst mal deine 'Pflicht', ehe es in die 'Kür' geht. 
Funktionspointer sind in C das, was im Eiskunstlauf der doppelte Axel 
ist. Du fängst erst damit an, wenn du das erste mal einen Nachmittag auf 
der Eisfläche ohne Hinfallen hinter dir hast. Ein ! nicht zuordnen zu 
können ist hingegen "Hinfallen nach 10 Sekunden"

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


Lesenswert?

hahahawahahaha

Karl Heinz Buchegger schrieb:
> Wozu wirfst du mit Funktionspoitner um dich, wenn du an den Grundlagen
> schon Schwierigkeiten hast.
> Erledige doch erst mal deine 'Pflicht', ehe es in die 'Kür' geht.
> Funktionspointer sind in C das, was im Eiskunstlauf der doppelte Axel
> ist. Du fängst erst damit an, wenn du das erste mal einen Nachmittag auf
> der Eisfläche ohne Hinfallen hinter dir hast.

Da hat Karl schon recht: erst ein C-Buch lesen, dann "bei Problemen" 
nachfragen. Allerdings sind Funktionspointer eigentlich auch nur Zeiger; 
das mit der doppelten Axel kann ich nicht nachvollziehen.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Karl Heinz Buchegger schrieb:
>> (wobei sorted logischerweise eine Variable ist, die boolschen Character
>> hat, also nur TRUE oder FALSE sein kann)
>
> was nicht so sein muss, in C kann es jede art von variable sein - sie
> muss nur auf 0 vergleichbar sein.

Wobei dann allerdings streng genommen

  while( sorted == FALSE )

nicht mehr das exakte Gegenteil von

  while( sorted != TRUE )

ist. Daher hab ich ja auch von "boolschem Charakter" gesprochen :-)

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


Lesenswert?

mann Klaus, bei dir geht aber auch manchmal die Logik durch...

Ich denke mal du meintest dass
while(sorted == FALSE)
nicht das Gleiche ist wie
while (sorted != TRUE)

Ist es nämlich auch nur bei "echten" Boolschen Variablen.

von Karl H. (kbuchegg)


Lesenswert?

Kan asta schrieb:

> das mit der doppelten Axel kann ich nicht nachvollziehen.

Gemeint war:
Ein Lernender benötigt so schnell keine Funktionspointer.
Und wenn er das erste mal darauf stösst und welche einsetzen will, dann 
dürfen solche Fragen wie eben die nach dem ! nicht mehr auftauchen.
Da die Frage aber auftaucht, ist die Schlussfolgerung: heb dir das für 
später auf. Zum jetzigen Zeitpunkt sind für dich Funktionspointer noch 
zu früh.

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


Lesenswert?

...vielleicht ist ja sogar C zu früh.
Ich rate zu Java, das ist wie C++ für Kinder...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ein schönes Beispiel für Funktionszeiger finde ich auch folgendes Modul.

Läuft ein C-Programm nicht auf einem PC sondern in einer non-hosted 
Umgebung wo es keine Console gibt, wissen Funktionen wie printf nicht, 
wo und wie sie ihre Eingabe abladen sollen.

Will man zum Beispiel ein Programm wie "Hallo Welt"
1
#include <stdio.h>
2
3
int main (void)
4
{
5
    printf ("Hallo Welt!\n");
6
7
    return 0;
8
}
Auf einem Mikrocontroller wie AVR laufen lassen, ist das printf quasi 
eine "Frau ohne Unterleib", den man erst bereitstellen muss.

Dazu überschreibt man stdout des Systems mit eigenen Versionsn, die 
Zeiger auf die eigenen Ausgabefunktionen erhalten und klinkt sich so 
transparent in die Ausgabe ein, d.h. am verwendenden Programm wie 
"Hallo Welt" muss nichts geändert werden.

Hier werden die Funktionen/Funktionszeiger als Callback verwendet, und 
die Callback-Verwendung von Funktionszeigern dürfte mithin die häufigste 
sein.

Das Modul stellt eine Verbindung zwischen stdout, stderr, stdin 
einerseits un UART-Routinen andererseits her. Die UART-Routinen selbst 
sind nicht in diesem Modul drinne; das Modul stellt lediglich das 
"Fräulein vom Amt" dar, das stdio mit UART verstöpselt.
1
#include <stdio.h>
2
#include "uart.h"
3
4
// Provide output and input function of proper prototypes to 
5
// feed in FDEV_SETUP_STREAM below.
6
7
static int
8
myio_putchar (char c, FILE *f)
9
{
10
    // We use this function to set up stdio et al., 
11
    // thus we do not need f.  The following line prevents the
12
    // compiler from complaining about the unused parameter f.
13
    (void) f;
14
    
15
    // uart_putchar is just a wrapper for the output function, 
16
    // so here we go for the output of char c in module uart.c:
17
    uart_putc (c);
18
19
#ifdef HOST_WINDOWS
20
    // For MS-Windows terminal: add "carriage return" after "newline"
21
    if (c == '\n')
22
        uart_putc ('\r');
23
#endif /* HOST_WINDOWS */
24
    
25
    return 0;
26
}
27
28
// Wrap uart_getc into proper prototyped function, too
29
30
static int
31
myio_getchar (FILE *f)
32
{
33
    // f is not needed, so once again we give gcc its pacifier
34
    (void) f;
35
36
    return uart_getc();
37
}
38
39
// Build up the FILE object for our UART communication
40
41
static FILE myio_stream = 
42
    FDEV_SETUP_STREAM (myio_putchar, myio_getchar, _FDEV_SETUP_RW);
43
44
// The following function will be called automatically before main.
45
46
static void __attribute__((constructor,used))
47
myio_setup_stdio (void)
48
{
49
    // Initialize UART. For UART mode (8N1) and baudrate see there.
50
    uart_init();
51
    
52
    // Let the standard streams point to our UART-stream objcet.
53
    stdout = &myio_stream;
54
    stdin  = &myio_stream;
55
    stderr = &myio_stream;
56
}

Schaut man sich das Präcompilat an, dann sieht die Definition von 
myio_stream so aus:
1
static struct __file myio_stream =
2
    { .put = myio_putchar,
3
      .get = myio_getchar,
4
      .flags = (0x0001|0x0002),
5
      .udata = 0,
6
    };

myio_setup_stdio wird übrigens als Constructor definiert und vor main 
aufgerufen, so daß in main printf et al. voll funktionsfähig sind.

Die Verwendung dieser I/O-Implementierung geschieht durch Hinzulinken 
des Moduls. Möchte man eine andere I/O-Implementierung, linkt man 
einfach ein anderes, entsprechend angepasstes Modul hinzu, das die 
Verdrahtung zu den gewünschten Ein-/Ausgabeprimitiven übernimmt.

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


Lesenswert?

...das ganze beispiel käme leider aber auch ohne Funktionspointer aus.
Mit Linkereinstellungen oder noch einfacher, mit Defines.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mit welchen Linkereinstellungen und Defines?

Zudem: Das Modul ist geschrieben um gut verständlich zu sein, nicht um 
das letzte Byte an Performance rauszuquetschen; dann ist printf eh 
obsolet.

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


Lesenswert?

#define printf newlib_printf

oder beim Linkeraufruf mit angeben. Ich glaub da kann man auch defines 
setzen...

von Christian B. (casandro)


Lesenswert?

Wobei ich sagen muss, dass das in C nicht so toll ist.
In anderen Sprachen geht das weiter und da haben Funktionszeiger auch 
richtige Typen. In anderen Sprachen geht man sogar so weit, dass man 
einen Funktionsblock so wie eine Variable handhaben kann. Damit kann man 
dann schicke Sachen machen.

Andere Anwendungen sind eine Form von Objektorientierung, oder 
Callback-Routinen in der ereignissgesteuerten Programmierung.

Wenn Du beispielsweise in Delphi/Lazarus ein Ereignis hast, so wird das 
als Funktionszeiger implementiert.

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


Lesenswert?

Kan asta schrieb:
> #define printf newlib_printf

Damit sind wir dann wirklich bei einer Gemeinheit von C.

Das, was du da versuchst, ist dir verboten.  printf ist (wenn man
ein #include <stdio.h> gemacht hat) ein reservierter Bezeichner,
an dem du dich nicht zu vergreifen hast. (*)

Im Übrigen würde dein Ansatz bei der ersten stdio-Funktion, die
nicht printf ist, ins Leere rennen, während bei Johanns Ansatz
wirklich das gesamte stdout ordentlich auf die Callback-Funktion
geleitet wird.  Es ist also egal, ob du putchar(), printf(),
fprintf(stdout, ...) oder puts() benutzt, alles kommt da raus, wo
es ankommen soll.

Außerdem musst du das Fahrrad (sprich, das Parsen des Formatstrings
und die Auswertung der Argumente) nicht nochmal erfinden wie in
einer eigenen printf-Implementierung.  Das macht die Bibliothek an
genau einer Stelle.

(*) Nur bei einem hosted environment, aber praktisch sind auch
Anwendungen auf Controllern wie dem AVR sinnvollerweise als ein
solches zu betrachten, weil man dann das Optimierungspotenzial des
Compilers besser ausnutzen kann.  Ein strlen("Hello") kann der
Compiler dann nämlich durch die Konstante 5 ersetzen, während er
beim Compilieren für ein freestanding environment zur Laufzeit die
Funktion strlen() aufzurufen gezwungen ist.

Christian Berger schrieb:
> In anderen Sprachen geht das weiter und da haben Funktionszeiger auch
> richtige Typen.

Ach, haben sie denn in C falsche Typen?

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


Lesenswert?

Jörg Wunsch schrieb:
> wenn man
> ein #include <stdio.h> gemacht hat

habe ich nicht.

Jörg Wunsch schrieb:
> Im Übrigen würde dein Ansatz bei der ersten stdio-Funktion, die
> nicht printf ist, ins Leere rennen

Kann die anderen Funktionen doch genauso umbiegen.


Jörg Wunsch schrieb:
> ußerdem musst du das Fahrrad (sprich, das Parsen des Formatstrings
> und die Auswertung der Argumente) nicht nochmal erfinden wie in
> einer eigenen printf-Implementierung.  Das macht die Bibliothek an
> genau einer Stelle.

Das Parsen des Formatstrings macht printf selbst, da muss man nix 
dazutun.

Es gibt viele Vor- und Nachteile; Johann wollte ein Beispiel, wie es 
ohne sein "Modul" geht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kan asta schrieb:
> #define printf newlib_printf

Nein. Das obige Modul Initialisiert auch den UART ohne Zutun in main.

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


Lesenswert?

Johann L. schrieb:
> Mit welchen Linkereinstellungen und Defines?

Du hast nachgefragt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wie gesagt, nur das Define tuts nicht. Wo kommt denn der Prototyp für 
die Funktion her? Und das angesprochene Initialisierungsproblem ist 
immer noch da. Entweder muss main verändert werden, oder es wird ein 
anderes Modul gebraucht.

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


Lesenswert?

Kan asta schrieb:
> Das Parsen des Formatstrings macht printf selbst, da muss man nix
> dazutun.

Dann verstehe ich überhaupt nicht, wie du das erreichen willst.

Ist aber auch egal.  Johann hatte ein Beispiel gebracht, bei dem die
Nutzung von Funktionszeigern zu einem relativ eleganten Design führt.
Wenn du ein Beispiel bringen willst, wie man auch ohne solche Zeiger
in einem ziemlich krückigen Design trotzdem noch eine einigermaßen
vergleichbare Funktionalität erreichen kann, sei dir das unbenommen,
aber dann mach' besser einen anderen Thread auf, denn in diesem hier
geht's um Funktionszeiger.

von Peter D. (peda)


Lesenswert?

Ein Beispiel für Funktionspointer ist auch mein Scheduler:

Beitrag "Wartezeiten effektiv (Scheduler)"

Damit kann man die zu verzögernde Funktion ganz einfach über ihren Namen 
einfügen.


Peter

von Micha (Gast)


Lesenswert?

ich hab zumindest zu der Frage ganz oben im ersten Beitrag, wozu man 
function pointer verwenden kann, ein praktisches Beispiel.

Hab nämlich eine Prozessor-Emulation in C geschrieben. Da kam mir die 
Möglichkeit, ein Array von function pointern zu verwenden, gerade recht. 
Die emulierten Maschinenbefehle sind entsprechend ihres Byte-Codes in 
einem function pointer array angelegt.Zunächst hatte ich es mittels 
"switch case" Konstrukt aufgebaut, aber den Code fand ich selber 
eigentlich schauderhaft schlecht. Und die Maschinencodes am hinteren 
Ende brauchten dann auch länger als die vorne dran. Da empfand ich das 
function pointer array als sehr elegante Alternative.

von Karl H. (kbuchegg)


Lesenswert?

Klassisches Beispiel für Funktionspointer ist ein allgemeines 
Menüsystem, bei dem per Pointer Funktionen an Menüpunkte gekoppelt 
werden.

von Rolf Magnus (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> aber praktisch sind auch Anwendungen auf Controllern wie dem AVR
> sinnvollerweise als ein solches zu betrachten, weil man dann das
> Optimierungspotenzial des Compilers besser ausnutzen kann.  Ein
> strlen("Hello") kann der Compiler dann nämlich durch die Konstante 5
> ersetzen, während er beim Compilieren für ein freestanding environment
> zur Laufzeit die Funktion strlen() aufzurufen gezwungen ist.

Mal blöd gefragt: Warum? Ist es einer freestanding-Implementation 
explizit verboten, eine Funktion namens strlen() zu haben, die durch 
besondere Maßnahmen optimiert ist?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Jörg Wunsch schrieb:
>> aber praktisch sind auch Anwendungen auf Controllern wie dem AVR
>> sinnvollerweise als ein solches zu betrachten, weil man dann das
>> Optimierungspotenzial des Compilers besser ausnutzen kann.  Ein
>> strlen("Hello") kann der Compiler dann nämlich durch die Konstante 5
>> ersetzen, während er beim Compilieren für ein freestanding environment
>> zur Laufzeit die Funktion strlen() aufzurufen gezwungen ist.
>
> Mal blöd gefragt: Warum? Ist es einer freestanding-Implementation
> explizit verboten, eine Funktion namens strlen() zu haben, die durch
> besondere Maßnahmen optimiert ist?

Natürlich kannst du eine optimierte strlen zur Verfügung stellen.
Aber aufgerufen werden muss die Funktion trotzdem, weil in einer 
nihct-hosted Umgebung strlen keine besondere Bedeutung hat und der 
Compiler keine Annahmen darüber machen darf .

Im von Jörg genannten Beispiel handelt es sich nicht um eine optimierte 
Implementierung von strlen, sondern darum, daß der Compiler wissen über 
strlen ausnutzt und es erst garnicht zu einem Aufruf von strlen kommt.

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> Natürlich kannst du eine optimierte strlen zur Verfügung stellen.
> Aber aufgerufen werden muss die Funktion trotzdem, weil in einer
> nihct-hosted Umgebung strlen keine besondere Bedeutung hat und der
> Compiler keine Annahmen darüber machen darf .

Für C an sich hat sie dann keine besondere Bedeutung, aber für den 
Compiler kann sie die doch trotzdem haben, oder nicht?

> Im von Jörg genannten Beispiel handelt es sich nicht um eine optimierte
> Implementierung von strlen,

Das ist mir schon klar, aber das da:

> sondern darum, daß der Compiler wissen über strlen ausnutzt und es erst
> garnicht zu einem Aufruf von strlen kommt.

ist das, was ich mit "durch besondere Maßnahmen optimiert" meinte. Die 
Funktion ist halt im Compiler eingebaut, und der kann dann verschiedene 
Maßnahmen ergreifen, um hier besser optimieren zu können, als es mit 
einer normalen Implementation der Funktion möglich wäre. Meine Frage war 
nun: Warum sollte er das bei einer freestanding-Implementation nicht 
dürfen? Daß es da keine Standardbibliothek und keine Standard-Funktion 
namens strlen() gibt, weiß ich, aber das muß ihn doch nicht davon 
abhalten, eine eigene Bibliothek mitzuliefern, wo's dann eben auch so 
eine Funktion gibt. Und wenn die zum Compiler gehört, kann er auch auch 
Annahmen darüber machen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

strlen kann nicht optimiert werden, weil es keine besondere Bedeutung 
hat, genauso wie hasenboppes keine besondere Bedeutung hat. Zitat aus 
GCC:

http://gcc.gnu.org/onlinedocs/gcc/Standards.html

>> The ISO C standard defines (in clause 4) two classes of
>> conforming implementation. A conforming hosted implementation
>> supports the whole standard including all the library facilities;
>> a conforming freestanding implementation is only required to
>> provide certain library facilities: those in <float.h>, <limits.h>,
>> <stdarg.h>, and <stddef.h>; since AMD1, also those in <iso646.h>;
>> since C99, also those in <stdbool.h> and <stdint.h>; and since C11,
>> also those in <stdalign.h> and <stdnoreturn.h>.
>> In addition, complex types, added in C99, are not required for
>> freestanding implementations.

Wie man sieht sind string.h, stdio.h, etc. nicht dabei.

von Stefan E. (sternst)


Lesenswert?

Rolf Magnus schrieb:
> Meine Frage war
> nun: Warum sollte er das bei einer freestanding-Implementation nicht
> dürfen? Daß es da keine Standardbibliothek und keine Standard-Funktion
> namens strlen() gibt, weiß ich, aber das muß ihn doch nicht davon
> abhalten, eine eigene Bibliothek mitzuliefern, wo's dann eben auch so
> eine Funktion gibt. Und wenn die zum Compiler gehört, kann er auch auch
> Annahmen darüber machen.

Und woher soll der Compiler wissen, dass auch seine eigene strlen() 
tatsächlich benutzt wird? Woher soll er wissen, dass der Code nicht in 
einem anderen Modul eine eigene strlen() mit anderen Eigenschaften hat?

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> strlen kann nicht optimiert werden, weil es keine besondere Bedeutung
> hat,

Nochmal: Ob sie im Bezug auf die C-Implementierung eine besondere 
Bedeutung hat, hat nichts damit zu tun, ob sie für diesen einen 
speziellen Compiler eine besondere Bedeutung hat.

> genauso wie hasenboppes keine besondere Bedeutung hat.

Wenn nun der Compiler eine Bibliothek mitliefert, in der es eine 
Funktion hasenboppes() gibt, wer verbietet dann dem Compiler, über genau 
diese Funktion genau dieser Bibliothek irgendwelche Annahmen zu machen?

Johann L. schrieb:
> Wie man sieht sind string.h, stdio.h, etc. nicht dabei.

Da steht aber auch:

>>> a conforming freestanding implementation is only required to
>>> provide certain library facilities

Nicht "only allowed", sondern "only required". Es ist ihr also nicht 
verboten, auch andere Teile der Library zu implementieren.

von Stefan E. (sternst)


Lesenswert?

Rolf Magnus schrieb:
> Wenn nun der Compiler eine Bibliothek mitliefert, in der es eine
> Funktion hasenboppes() gibt, wer verbietet dann dem Compiler, über genau
> diese Funktion genau dieser Bibliothek irgendwelche Annahmen zu machen?

Wenn im Code die Funktion hasenboppes() aufgerufen wird, kann der 
Compiler gar nicht wissen, ob letztlich die von ihm in der Library 
angebotene Implementierung benutzt wird, oder eine ganz andere (andere 
Lib, oder direkt im Code). Und bei freestanding ist das bei strlen() 
genauso.

von Nico S. (nico22)


Lesenswert?

Rolf Magnus schrieb:
> Nicht "only allowed", sondern "only required". Es ist ihr also nicht
> verboten, auch andere Teile der Library zu implementieren.

Genau so lese ich diese Passage übrigens auch.

/EDIT:
Was hält dem Compiler eigentlich davon ab festzustellen, dass die 
Funktion strlen völlig reentrant ist und das Argument ohnehin konstant 
ist und sie deswegen zur Kompilierzeit auszuführen? Ist das im Standard 
explizit verboten?

von Stefan E. (sternst)


Lesenswert?

Nico Sch. schrieb:
> Was hält dem Compiler eigentlich davon ab festzustellen, dass die
> Funktion strlen völlig reentrant ist und das Argument ohnehin konstant
> ist und sie deswegen zur Kompilierzeit auszuführen?

Bei hosted passiert doch genau das. Und bei freestanding geht das nicht, 
weil ... (ach, keine Lust das jetzt ein drittes Mal zu schreiben)

von Nico S. (nico22)


Lesenswert?

Stefan Ernst schrieb:
> weil ... (ach, keine Lust das jetzt ein drittes Mal zu schreiben)

Wenn er die Funktion im Quelltext vorliegen hat? Beispielsweise, weil 
sie böserweise in einem Header definiert ist?

von Stefan E. (sternst)


Lesenswert?

Nico Sch. schrieb:
> Wenn er die Funktion im Quelltext vorliegen hat? Beispielsweise, weil
> sie böserweise in einem Header definiert ist?

Ich weiß nicht, worauf du damit jetzt hinaus willst? In dem Fall greifen 
natürlich alle Optimierungen, die auch für jede beliebige andere 
Funktion im Source greifen würde, inklusive Inlining, ersetzen von 
Variablen durch Konstanten, etc.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:
> Johann L. schrieb:
>> strlen kann nicht optimiert werden, weil es keine besondere Bedeutung
>> hat,
>
> Nochmal: Ob sie im Bezug auf die C-Implementierung eine besondere
> Bedeutung hat, hat nichts damit zu tun, ob sie für diesen einen
> speziellen Compiler eine besondere Bedeutung hat.

Doch; wenn der Compiler eine C-complaint implementation darstellen soll, 
schon.

Hier über nicht-standardkonforme Compiler zu reden ist wenig sinnvoll; 
die dürfen natürlich alles.

> Johann L. schrieb:
>> Wie man sieht sind string.h, stdio.h, etc. nicht dabei.
>
> Da steht aber auch:
>
>>>> a conforming freestanding implementation is only required to
>>>> provide certain library facilities

Beispiel: va_start, va_arg und va_end aus stdarg.h

> Nicht "only allowed", sondern "only required". Es ist ihr also nicht
> verboten, auch andere Teile der Library zu implementieren.

Welche Library denn???

Oben ist keine Library/Header aufgezählt, die ein strlen spezifiziert!

Und da strlen damit im Namespace der Anwendung ist und nicht im 
Namespace der Implementierung, hat ein Compiler da nix dran 
rumzufutscheln und sich eine eigene Semantik aus den Fingern zu saugen — 
egal wie plausibel diese für einen Anwender sein mag.

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


Lesenswert?

(Ist schon ein bisschen länger her, ich gehe gerade alte Threads durch,
zu denen ich mal was geschrieben hatte.)

Nico Sch. schrieb:
> Stefan Ernst schrieb:
>> weil ... (ach, keine Lust das jetzt ein drittes Mal zu schreiben)
>
> Wenn er die Funktion im Quelltext vorliegen hat? Beispielsweise, weil
> sie böserweise in einem Header definiert ist?

Du meinst, ein Compiler würde Quellcode verstehen und könnte aus
diesem Quellcode:
1
int strlen(const char *cp)
2
{
3
  int i = 0;
4
  while (*cp++ != 0)
5
    i++;
6
  return i;
7
}

schlussfolgern, dass ein
1
  memcpy(s, "Hello, world!", strlen("Hello, world!"));

durch
1
  memcpy(s, "Hello, world!"), 13);

ersetzbar ist?  Nein, dazu müsste der Compiler ja den Code der
Target-Maschine selbst ablaufen lassen.

Ein Compiler ist eine Maschine, kein Mensch mit Intelligenz.

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.