Ich habe das mit zusammengestellt nargs Es wäre undefiniertes Verhalten, wenn die
Der Parameter stimmte nicht mit der Anzahl der Argumente überein, die die Funktion verwendet hat, aber ist es zulässig, wenn es eine Übereinstimmung gibt? void* Nicht die Antwort auf Ihre spezifische Frage, aber der übliche Ansatz besteht darin, nur einen Funktionszeiger zu haben, der a akzeptiert NULL -Parameter und interpretieren ihn dann je nach tatsächlicher Implementierung unterschiedlich. Dieser Parameter kann dann beliebig sein
zu einem Zeiger auf eine Struktur mit einem Dutzend Parametern. Wenn der Aufrufer die Anzahl, den Typ und die Reihenfolge der Parameter kennen muss, wird die ganze Idee in der Praxis weniger nützlich.
– Groo
21. Mai 2020 um 12:25 Uhr
Der Abstand in dem Code, den Sie gepostet haben, macht mich irrational wütend.
– Konrad Rudolf
21. Mai 2020 um 21:14 Uhr mainEs wäre eine gute Praxis, die Abgüsse zu entfernen
. Im Allgemeinen können solche Umwandlungen dazu führen, dass der Compiler die Diagnose für fehlerhafte Konvertierungen unterdrückt.
– MM
21. Mai 2020 um 23:01 Uhr Unabhängig davon, ob diese Art der Konstruktion streng istlegal fun0 würde ich argumentieren, dass es sauberere Möglichkeiten gibt, dasselbe zu erreichen (zum Beispiel have
nimm ein Argument an und ignoriere es einfach).
– bta
22. Mai 2020 um 1:18 Uhr mnemonic op1, op2@KonradRudolph: Mein erster Eindruck in der ersten Sekunde, als ich den Codeblock sah, war, nur basierend auf dem Abstand, dass es wie Assemblersprache aussah (basierend auf mehreren tabulatorgestoppten Spalten, wie sie asm verwenden würde
). Ich sagte: “Das war von HNQ, warum habe ich das nicht in der Liste der aktiven Asm-Fragen gesehen?” Ich mag diesen Abstand für C auch nicht!
buchstabiert, was zwei Funktionstypen kompatibel macht (relevanter Teil in Fettdruck): Damit zwei Funktionstypen kompatibel sind, müssen beide kompatible Rückgabetypen angeben. Darüber hinaus müssen die Parametertyplisten, falls beide vorhanden sind, in der Anzahl der Parameter und in der Verwendung des Auslassungszeichens übereinstimmen; entsprechende Parameter müssen kompatible Typen haben. Wenn ein Typ eine Parametertypliste hat und der andere Typ durch einen Funktionsdeklarator angegeben wird, der nicht Teil einer Funktionsdefinition ist und eine leere Bezeichnerliste enthält, darf die Parameterliste kein Auslassungszeichen haben und der Typ jedes Parameters muss mit dem Typ kompatibel sein, der sich aus der Anwendung der Standardargument-Promotions ergibt.
Wenn ein Typ eine Parametertypliste hat und der andere Typ durch eine Funktionsdefinition spezifiziert wird, die eine (möglicherweise leere) Bezeichnerliste enthält, müssen beide in der Anzahl der Parameter übereinstimmen, und der Typ jedes Prototypparameters muss mit dem Typ kompatibel sein das ergibt sich aus der Anwendung der Default-Argument-Promotions auf den Typ des entsprechenden Bezeichners. (Bei der Bestimmung der Typkompatibilität und eines zusammengesetzten Typs wird angenommen, dass jeder mit einem Funktions- oder Array-Typ deklarierte Parameter den angepassten Typ hat, und jeder mit einem qualifizierten Typ deklarierte Parameter wird so behandelt, als hätte er die nicht qualifizierte Version seines deklarierten Typs.) typedef Sie haben also eine
void()
mit Typ:
void(void)
void(double)
Und Funktionen mit Typ:...Die beiden Funktionsdefinitionen verwenden keine Auslassungspunkte ( ), so dass die erste Bedingung erfüllt ist. Schauen wir uns für die zweite Bedingung an, was die Standardargument-Promotions
sind. Diese sind in Abschnitt 6.5.2.2p6 spezifiziert: float Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der keinen Prototyp enthält, werden die ganzzahligen Heraufstufungen für jedes Argument und für Argumente, die einen Typ haben, durchgeführt doubledazu befördert werden . Diese heißen dieStandardargument-Promotions
. double Die erste Funktion hat keine Argumente, ist also kompatibel. Die zweite Funktion hat eine Single
-Argument, das mit den Standardargument-Promotions übereinstimmt, also auch kompatibel ist.
void f1(long);
void f2(int);
Um einige weitere Beispiele zu nennen, die folgenden Funktionen wären ebenfalls kompatibel:
void f3(float);
void f4(char);
void f5(short);
Benutzer-Avatar
StoryTeller – Unslander Monica Wie eine andere Antwort feststellt, ist der von Ihnen gezeigte Code gültig Cheute
. Dies kann sich jedoch aufgrund der Verwendung eines Funktionstyps ohne Parameterliste jederzeit in der Zukunft ändern.
Die Verwendung von Funktionsdeklaratoren mit leeren Klammern (keine Parametertypdeklaratoren im Prototypformat) ist ein veraltetes Feature.
Eine obsolete Funktion wird in zukünftigen Standardversionen entfernt. Wenn Sie also möchten, dass Ihr Code zukunftssicher ist, sollten Sie dies am besten vermeiden.
Vielen Dank. Leider scheint es mir ein bisschen hart zu sagen, dass diese Funktion veraltet ist.
– dmuir
21. Mai 2020 um 12:54 Uhr Dieser Abschnitt bezieht sich speziell auf die FunktionDeklaratoren void f(); . Es sagt, dass das Deklarieren einer Funktion als void() ist veraltet; es heißt nicht, dass die Existenz des Funktionstyps void (*)() oder der Zeigertyp
ist obsolet. (Ich weiß nicht, was die zugrunde liegende Absicht war, aber der wörtliche Text spricht nur von Deklaratoren.)
– Benutzer2357112
22. Mai 2020 um 0:32 Uhrint main()@ user2357112supportsMonica Auf diese Weise ist der obige Code für arme Programmierer-Generika immer noch gültig, aber Funktionsdeklarationen im K & R-Stil ( void ) nicht mehr. Viele unterlassen die Hier würde das Denken “keine Argumente” bedeuten, obwohl es “unbestimmte Zahl” bedeutet, wenn es als eigenständige Deklaration verwendet wird, und “keine Argumente”.aber kein Prototyp
” wenn es als Teil einer Funktionsdefinition verwendet wird. In beiden Fällen warnt der Compiler nicht, wenn Sie versehentlich Argumente übergeben, und im zweiten Fall handelt es sich definitiv um ein undefiniertes Verhalten.
– ljrk
22. Mai 2020 um 8:44 Uhr void (*)() @ user2357 – Ein Deklarator ist ein syntaktisches Konstrukt, das zum Erstellen von Deklarationen verwendet wird. Und einige Typen werden von Deklaratoren abgeleitet.
enthält einen Funktionsdeklarator über einem Zeigerdeklarator. Wie genau wird der Typ ohne die Syntax zu seiner Erstellung weiter existieren!??
Wie in der Antwort von @StoryTeller erwähnt, ist die Verwendung von Funktionsdeklaratoren mit leeren Klammern eine veraltete Funktion, die jedoch vermieden werden kann: main EDIT: Geänderte Parameterliste von void zu
für die Einhaltung.
Als Antwort auf die Anfrage:
“Außerdem müssen die Parametertyplisten, falls beide vorhanden sind, in der Anzahl der Parameter übereinstimmen” scheint zu bedeuten, dass die Typen von funp und von fun1 nicht kompatibel sind. Ist es ok zu casten? Die Antwort ist ja, es ist in Ordnung zu casten. Aus C11-Entwurf6.3.2.3 Abs. 8
:
Ein Zeiger auf eine Funktion eines Typs kann in einen Zeiger auf eine Funktion eines anderen Typs umgewandelt werden und wieder zurück; das Ergebnis soll mit dem ursprünglichen Zeiger verglichen werden. Wenn ein konvertierter Zeiger verwendet wird, um eine Funktion aufzurufen, deren Typ nicht mit dem referenzierten Typ kompatibel ist, ist das Verhalten undefiniert. fun1 Im Code ist der Zeiger auf funcallwurde im Aufruf von in einen anderen Funktionszeigertyp konvertiert funcall und darin wieder in den ursprünglichen Typ konvertiert fun1kann also zum Anrufen verwendet werden
.
Aus dem Auszug von dbush aus der Spezifikation “Darüber hinaus müssen die Parametertyplisten, wenn beide vorhanden sind, in der Anzahl der Parameter übereinstimmen” zu bedeuten scheint, dass die Typen von funp und fun1 nicht kompatibel sind. Ist es ok zu casten?
– dmuir
21. Mai 2020 um 14:47 Uhr @dmuir die erforderliche Kompatibilität liegt zwischen die aufgerufene Funktion undder Ausdruck des Funktionsaufrufs
. Es spielt keine Rolle, ob ein anderer Typ verwendet wurde, um den Funktionszeiger zu transportieren, bevor wir zum Funktionsaufrufausdruck kamen.
– MM
21. Mai 2020 um 23:03 Uhr main @MM Huh, es gibt zwei Bedingungen, die erste betrifft die Typen (gegen die dies verstößt) und die zweite die Ausdrücke (gut). Allerdings sollte OPs Code meiner Meinung nach in Zukunft sogar in Ordnung sein, da die Typedef keine Funktionsdeklaration und damit legitim ist. Allerdings die Funktionsdeklaration
in dieser Antwort ist nicht :p
– ljrk
22. Mai 2020 um 8:49 Uhr
@larkey mir ist nicht klar, was du mit “dem ersten” meinst, könntest du ein Standardzitat liefern und / oder näher erläutern. Das Programm in dieser Antwort ist genau definiert
– MM
22. Mai 2020 um 8:55 Uhr main Ich habe das behoben
Parameterliste (habe es vorher nie bemerkt!) und Sachen über die Umwandlung von Funktionszeigern hinzugefügt.
Der Parameter stimmte nicht mit der Anzahl der Argumente überein, die die Funktion verwendet hat, aber ist es zulässig, wenn es eine Übereinstimmung gibt?
void*
Nicht die Antwort auf Ihre spezifische Frage, aber der übliche Ansatz besteht darin, nur einen Funktionszeiger zu haben, der a akzeptiertNULL
-Parameter und interpretieren ihn dann je nach tatsächlicher Implementierung unterschiedlich. Dieser Parameter kann dann beliebig seinzu einem Zeiger auf eine Struktur mit einem Dutzend Parametern. Wenn der Aufrufer die Anzahl, den Typ und die Reihenfolge der Parameter kennen muss, wird die ganze Idee in der Praxis weniger nützlich.
– Groo
21. Mai 2020 um 12:25 Uhr
Der Abstand in dem Code, den Sie gepostet haben, macht mich irrational wütend.
– Konrad Rudolf
21. Mai 2020 um 21:14 Uhr
main
Es wäre eine gute Praxis, die Abgüsse zu entfernen. Im Allgemeinen können solche Umwandlungen dazu führen, dass der Compiler die Diagnose für fehlerhafte Konvertierungen unterdrückt.
– MM
21. Mai 2020 um 23:01 Uhr Unabhängig davon, ob diese Art der Konstruktion streng istlegal
fun0
würde ich argumentieren, dass es sauberere Möglichkeiten gibt, dasselbe zu erreichen (zum Beispiel havenimm ein Argument an und ignoriere es einfach).
– bta
22. Mai 2020 um 1:18 Uhr
mnemonic op1, op2
@KonradRudolph: Mein erster Eindruck in der ersten Sekunde, als ich den Codeblock sah, war, nur basierend auf dem Abstand, dass es wie Assemblersprache aussah (basierend auf mehreren tabulatorgestoppten Spalten, wie sie asm verwenden würde). Ich sagte: “Das war von HNQ, warum habe ich das nicht in der Liste der aktiven Asm-Fragen gesehen?” Ich mag diesen Abstand für C auch nicht!
– Peter Cordes