Und noch eine Frage. Wie werden in diesem Fall Zeiger auf Funktionen richtig deklariert und verwendet?
@SouravGhosh: Das ist nicht das Problem. Ein Vermisstes -lm würde einen Linker-Fehler verursachen.
– Keith Thompson
2. Februar 2015 um 16:54 Uhr
@KeithThompson Richtig, Sir. Mein Fehler.
– Sourav Ghosh
2. Februar 2015 um 16:55 Uhr
@SouravGhosh Keine Notwendigkeit, sich zu entschuldigen. Löschen Sie einfach die falschen und ablenkenden Kommentare und fahren Sie fort.
– Jonathon Reinhart
2. Februar 2015 um 16:56 Uhr
Ich denke, es hat damit zu tun, wie Assembler funktioniert, die Variable x wird in einem Register gehalten, zum Beispiel %ebx, und Sie rufen die auf Funktion mit einem Argument, aber in Wirklichkeit werden 2 Argumente verwendet, also wird angenommen, dass das zweite Argument in %ebx ist. // Ich bin mir nicht sicher
– KarimS
2. Februar 2015 um 16:56 Uhr
Er fragte auch, warum der Code funktioniert. Er übergibt den Wert von x nicht an pow und erhält dennoch korrekte Ergebnisse.
– Sandsack_1996
2. Februar 2015 um 16:57 Uhr
Keith Thompson
Dies:
void aux(double (*function)(), double n, double x);
verwendet eine Nicht-Prototyp-Deklaration im alten Stil für function. Die leeren Klammern () bedeutet, dass die Funktion eine feste, aber nicht spezifizierte Anzahl und Art(en) von Argumenten akzeptiert.
C lässt diese Art der Deklaration aus Gründen der Abwärtskompatibilität immer noch zu. Prototypen (Funktionsdeklarationen, die die Typen der Parameter angeben) wurden 1989 von ANSI C eingeführt. Davor war es nicht möglich, Parametertypen in einer Funktionsdeklaration anzugeben, und Compiler konnten nicht prüfen, ob ein Aufruf die richtige Zahl und übergab Art(en) von Argumenten.
Solche Deklarationen sind „veraltet“, was bedeutet, dass die Unterstützung für sie aus einem zukünftigen C-Standard entfernt werden könnte (aber in mehr als 20 Jahren ist das Komitee nicht dazu gekommen, sie zu entfernen). Der Aufruf einer Funktion mit der falschen Anzahl von Argumenttypen wird nicht unbedingt vom Compiler diagnostiziert, und das Verhalten ist undefiniert.
Die Regeln für Kompatibilität von Funktionstypen sind etwas kompliziert, wenn einer einen Prototyp hat und der andere nicht. Diese Typen:
double(double) /* function with one double parameter
returning double */
double(double, double) /* function with two double parameters
returning double */
sind nicht miteinander kompatibel, aber sie sind beide kompatibel mit diesem Typ:
double() /* function with a fixed but unspecified number of parameters
returning double */
Dadurch sind fehlerhafte Aufrufe ohne Diagnose des Compilers möglich.
Um dieses Problem zu vermeiden, Verwenden Sie immer Prototypen:
void aux(double (*function)(double, double), double n, double x);
Sie erhalten nicht nur eine bessere Diagnose von Ihrem Compiler, Sie müssen sich auch keine Gedanken über die komplizierten Kompatibilitätsregeln für nicht prototypisierte Funktionen machen (die, wenn Sie neugierig sind, in N1570 6.7.6.3 Absatz 16).
Ich frage mich immer noch, wie nur ein Argument dazu führt pow oder sqrt Berechnung?
– Hacken
2. Februar 2015 um 16:59 Uhr
@hackks: Sie können sich für immer wundern. Das Verhalten ist nicht definiert. Im Prinzip kann es sich ändern, wenn Sie Ihr Programm das nächste Mal ausführen. Sie können es nicht vorhersagen, und Sie können es nur erklären, indem Sie die Binärdatei zerlegen, um den Code zu untersuchen, den der Compiler tatsächlich generiert hat. Sie können nicht davon ausgehen, dass der Compiler beim nächsten Kompilieren Ihres Programms denselben Code generiert.
– Johannes Bollinger
2. Februar 2015 um 17:05 Uhr
@cmaster: Ich denke schon -Wmissing-prototypes das veranlasst GCC, solche Warnungen auszugeben. Ich weiß, dass es das kann, da ich bei der Arbeit mit Legacy-Code Berge solcher Warnungen sortieren musste.
– Johannes Bollinger
2. Februar 2015 um 18:26 Uhr
@chux: Sie können sich sicher sein, aber ich fürchte, Sie irren sich. Sehen N1570 6.7.6.3 Absatz 16. int printf(); ist nicht kompatibel mit int printf(const char *format, ...);. gcc sagt “eine Parameterliste mit Auslassungspunkten kann nicht mit einer leeren Parameternamenlistendeklaration übereinstimmen”. Übrigens, (...) ohne mindestens einen expliziten Parameter ist illegal; der letztgenannte Parameter wird für benötigt va_start().
– Keith Thompson
2. Februar 2015 um 18:53 Uhr
@chux: Die Legacy-Version war <varargs.h>. Es ist va_start() Makro benötigte keinen benannten Parameter und begann immer mit dem allerersten Parameter. pubs.opengroup.org/onlinepubs/7908799/xsh/varargs.h.html. Wie für (...) vs. ()Ich denke, wir können uns darauf einigen, dass das Veralten vermieden wird () Form ist eine gute Idee.
– Keith Thompson
2. Februar 2015 um 20:05 Uhr
Ihr Prototyp für Funktion aux()…
void aux(double (*function)(), double n, double x);
… gibt an, dass das erste Argument ein Zeiger auf eine zurückkehrende Funktion ist double und Akzeptieren von nicht spezifizierten Argumenten. Dadurch wird verhindert, dass GCC Warnungen über nicht übereinstimmende Typen für die Aufrufe dieser Funktion in ausgibt main().
Allerdings funktionieren aux()‘s Definition gibt einen spezifischeren Typ für seinen ersten Parameter an, einen, der mit den eigentlichen Argumenten, die Sie übergeben, nicht kompatibel ist. Der Aufruf dieser Funktionen über den Zeiger hat undefinierte Semantik. Es könnte so ziemlich alles passieren, einschließlich, dass das Verhalten so aussieht, wie Sie es wollten. Sie können sich auf nichts über dieses Verhalten verlassen.
meinaut
Weil Sie den Prototyp von angegeben haben aux() vor Haupt- u function hat keine angegebenen Argumenttypen. Lerne den Unterschied:
void f(); /* Accepts any number of arguments thanks to K&R C */
void g(void); /* No arguments accepted */
void h(int); /* Only one integer argument accepted */
Wenn Sie erklären aux() Prototyp als:
void aux(double (*function)(double), double n, double x);
GCC beginnt sich zu beschweren.
Ein leeres Klammerpaar () teilt dem C-Compiler mit, dass die Funktion mit aufgerufen werden kann irgendein Anzahl von Parametern, sondern dass die Funktion selbst eine bestimmte Anzahl von Parametern für ihren Prototyp hat. Wenn Sie es also mit einem Funktionszeiger verwenden und die Anzahl und die jeweiligen Typen der übergebenen Parameter mit dem Prototyp der Funktion, auf die gezeigt wird, übereinstimmen, funktioniert alles. Wenn Sie jedoch die Parameterliste aushungern oder anders typisierte Werte verwenden … nun, das ist ein undefiniertes Verhalten.
13115700cookie-checkWarum funktioniert dieser Zeiger auf die Funktion ohne Warnungen oder Fehler?yes
@SouravGhosh: Das ist nicht das Problem. Ein Vermisstes
-lm
würde einen Linker-Fehler verursachen.– Keith Thompson
2. Februar 2015 um 16:54 Uhr
@KeithThompson Richtig, Sir. Mein Fehler.
– Sourav Ghosh
2. Februar 2015 um 16:55 Uhr
@SouravGhosh Keine Notwendigkeit, sich zu entschuldigen. Löschen Sie einfach die falschen und ablenkenden Kommentare und fahren Sie fort.
– Jonathon Reinhart
2. Februar 2015 um 16:56 Uhr
Ich denke, es hat damit zu tun, wie Assembler funktioniert, die Variable x wird in einem Register gehalten, zum Beispiel %ebx, und Sie rufen die auf Funktion mit einem Argument, aber in Wirklichkeit werden 2 Argumente verwendet, also wird angenommen, dass das zweite Argument in %ebx ist. // Ich bin mir nicht sicher
– KarimS
2. Februar 2015 um 16:56 Uhr
Er fragte auch, warum der Code funktioniert. Er übergibt den Wert von x nicht an pow und erhält dennoch korrekte Ergebnisse.
– Sandsack_1996
2. Februar 2015 um 16:57 Uhr