C: Nicht angegebene Anzahl von Parametern - void foo ()

9

Ich lese hier das in C void foo() bedeutet a function foo taking an unspecified number of arguments of unspecified type .

Kann mir jemand ein Beispiel geben oder zeigen, wo eine C Funktion eine unbestimmte Anzahl von Argumenten benötigt? Wofür kann dies in C angewendet werden? Ich konnte nichts im Internet finden.

Danke!

    
Jacob Krieg 27.02.2014, 16:04
quelle

4 Antworten

12

Das ist eine alte Funktionsdeklaration.

Diese Erklärung:

%Vor%

deklariert, dass foo eine Funktion ist, die void zurückgibt, die eine nicht spezifizierte, aber feste Anzahl und Typen von Argumenten benötigt. Es bedeutet nicht, dass Aufrufe mit beliebigen Argumenten gültig sind; Dies bedeutet, dass der Compiler keine falschen Aufrufe mit der falschen Anzahl oder Art von Argumenten diagnostizieren kann.

Irgendwo, vielleicht in einer anderen Übersetzungseinheit (Quelldatei), muss es eine Definition der Funktion geben, vielleicht:

%Vor%

Dies bedeutet, dass jeder Aufruf von foo , das nicht zwei Argumente vom Typ long und double* übergibt, ungültig ist und nicht definiert ist.

Vor dem 1989 ANSI C-Standard waren dies die einzige Art von Funktionsdeklaration und -definition, die in der Sprache verfügbar waren, und die Last, korrekte Funktionsaufrufe zu schreiben, lag ausschließlich beim Programmierer. ANSI C fügte Prototypen hinzu, Funktionsdeklarationen, die die Typen der Parameter einer Funktion angeben, die eine Überprüfung der Funktionsaufrufe zur Kompilierungszeit ermöglichen. (Diese Funktion wurde von frühem C ++ übernommen.) Das moderne Äquivalent des obigen wäre:

%Vor%

Old-style (Nicht-Prototyp) Deklarationen und Definitionen sind immer noch legal, aber sie sind offiziell veraltet , was bedeutet, dass sie im Prinzip aus einer zukünftigen Version der Sprache entfernt werden könnten - obwohl sie immer noch in der Norm von 2011 sind, weiß ich nicht, dass das jemals tatsächlich passieren wird.

Es gibt keinen guten Grund, im modernen C-Code alte Funktionsdeklarationen und Definitionen zu verwenden. (Ich habe Argumente dafür gesehen, sie in einigen Fällen zu verwenden, aber ich finde sie nicht überzeugend.)

C unterstützt auch variadic Funktionen wie printf , die eine beliebige Anzahl von Argumenten enthalten, aber das ist ein besonderes Merkmal. Eine Variadic-Funktion muss mit einem Prototyp deklariert werden, der ein abschließendes , ... enthält. (Das Aufrufen einer variadischen Funktion ohne sichtbaren Prototyp ist nicht illegal, hat aber ein undefiniertes Verhalten.) Die Funktion selbst verwendet Makros, die in <stdarg.h> definiert sind, um ihre Parameter zu verarbeiten. Wie bei alten Funktionsdeklarationen gibt es keine Kompilierzeitprüfung für Argumente, die , ... entsprechen (obwohl einige Compiler einige Aufrufe überprüfen können; z. B. gcc warnt, wenn die Argumente in einem printf -Aufruf nicht mit dem Format übereinstimmen) Zeichenfolge).

    
Keith Thompson 27.02.2014, 16:17
quelle
2

Die Deklaration void foo(); ist nicht notwendigerweise das Gleiche wie eine Funktion, die eine variable Anzahl von Argumenten akzeptiert.

Alles, was es ist, ist eine Funktionsdeklaration, die nothing über die Anzahl der Argumente, die die Funktion benötigt, angibt (tatsächlich ist das nicht genau richtig, siehe unten über Argument-Promotions). Die Deklaration ist kein Funktionsprototyp, der Informationen über die Anzahl und die Typen der Parameter bereitstellt (mithilfe von Auslassungspunkten werden Parameter mit variabler Länge angegeben).

Die Funktion definition (wo der Rumpf der Funktion bereitgestellt wird) könnte eine feste Anzahl von Argumenten haben und könnte sogar einen Prototyp haben.

Wenn eine solche Funktionsdeklaration verwendet wird, ist es Sache des Programmierers, foo() aufzurufen, um die Argumente zu erhalten, die foo() erwartet (und deren Typen) - der Compiler hat keine Informationen über die Argumentliste foo() benötigt. Es schränkt auch den Typ der Parameter ein, die die Funktionsdefinition verwenden kann, da beim Aufruf der Funktion ohne einen Prototyp die Standardargument-Aktionen auf die Argumente beim Funktionsaufruf angewendet werden. So kann eine Funktion, die ohne einen Prototyp deklariert wird, nur erwartete Argumente erwarten.

Siehe die folgenden C99-Standardabschnitte für einige Details:

  

6.7.5.3/14 "Funktionsdeklaratoren (einschließlich Prototypen)

     

...

     

Die leere Liste in einem Funktionsdeklarator, der nicht Teil von a ist   Definition dieser Funktion gibt an, dass keine Informationen über die   Anzahl oder Typen der Parameter wird angegeben.

     

...

     

6.5.2.2 Funktionsaufrufe

     

...

     

Wenn der Ausdruck, der die aufgerufene Funktion bezeichnet, einen Typ hat, der   enthält keinen Prototyp, an dem Ganzzahl-Promotions ausgeführt werden   Jedes Argument und alle Argumente, die den Typ float haben, werden in promoted   doppelt. Dies nennt man die Standard-Argument-Promotion. Wenn die   Anzahl der Argumente ist nicht gleich der Anzahl der Parameter, die   Verhalten ist nicht definiert. Wenn die Funktion mit einem Typ definiert ist, der   enthält einen Prototyp, und entweder endet der Prototyp mit einer Ellipse   (, ...) oder die Arten der Argumente nach der Promotion sind nicht   kompatibel mit den Typen der Parameter ist das Verhalten   nicht definiert. Wenn die Funktion mit einem Typ definiert ist, der dies nicht tut   Fügen Sie einen Prototyp und die Typen der Argumente nach dem Hochstufen ein   sind nicht mit denen der Parameter nach der Förderung kompatibel, die   Das Verhalten ist nicht definiert, mit Ausnahme der folgenden Fälle:

     
  • ein heraufgestufter Typ ist ein vorzeichenbehafteter Integer-Typ, der andere hochgestufte Typ ist der entsprechende vorzeichenlose Integer-Typ, und der Wert ist   in beiden Typen darstellbar;
  •   
  • beide Typen sind Zeiger auf qualifizierte oder nicht qualifizierte Versionen eines Zeichentyps oder void.
  •   
    
Michael Burr 27.02.2014 16:36
quelle
1

Dies bedeutet wörtlich, dass Sie dem Compiler nicht sagen, welche Argumente die Funktion benötigt, das heißt, dass Sie nicht davor geschützt sind, sie mit einem beliebigen Satz von Argumenten aufzurufen. Sie müssten in der Definition genau sagen, welche Argumente tatsächlich für die zu implementierende Funktion verwendet werden.

Sie könnten dies beispielsweise verwenden, wenn Sie eine Header-Datei zum Beschreiben einer fremden Funktion in externem Code generieren. Wenn Sie jedoch nicht wissen, wie die Signatur der Funktion tatsächlich lautet, ist sie unter Verwendung Ihrer Kopfzeile dennoch aufrufbar Die falschen Argumente in den Anrufergebnissen sind nicht definiert.

    
Vality 27.02.2014 16:17
quelle
1

Der Call-Standard der C-Funktion ermöglicht den Aufruf einer Funktion mit null oder mehr Argumenten und die Anzahl der Argumente kann mit der Funktionsschnittstelle übereinstimmen oder nicht.

Das funktioniert wie folgt: Der Aufrufer muss den Stack anpassen, nachdem die aufgerufene Funktion zurückgegeben wurde, und nicht die aufgerufene Funktion, um den Stack anzupassen, wie dies bei anderen Standards wie Pascal der Fall ist.

Da der Aufrufer weiß, welche Argumente und deren Typen auf den Stapel geschoben wurden, bevor die aufgerufene Funktion aufgerufen wird und die aufgerufene Funktion nicht, ist es dem Aufrufer überlassen, die übergebenen Argumente vom Stapel zu löschen, nachdem die aufgerufene Funktion zurückgegeben wurde .

Mit aktualisierten C-Standards ist die Beschreibung der Funktionsaufrufschnittstelle komplexer geworden, damit der Compiler Schnittstellenprobleme erkennen und melden kann, die der ursprüngliche K & amp; C-Standard vom Compiler nicht erkannt bekommen hat.

Der Standard besteht nun darin, dass Sie Variablenargumentlisten mit der Elipsis-Notation von drei Punkten oder Punkten nach dem letzten bekannten und angegebenen Argument in der Schnittstellenspezifikation oder Deklaration der aufgerufenen Funktionen angeben.

Sie würden also für einige der Standard-C-Bibliothek-E / A-Funktionen Folgendes sehen:

%Vor%

Dies zeigt an, dass die Funktion sprintf erfordert, dass das erste Argument ein char-Zeiger auf einen Puffer ist, das zweite Argument ein char-Zeiger auf eine Formatzeichenfolge ist und dass möglicherweise noch weitere Argumente vorhanden sind. In diesem Fall wären zusätzliche Argumente erforderlich, die für die Druckformatbezeichner in der Formatzeichenfolge eingefügt werden müssen. Wenn die Formatzeichenkette nur eine Textzeichenfolge ist, für die kein Format angegeben ist (etwas wie zB% d für eine ganze Zahl), gäbe es keine anderen Argumente.

Die neueren C-Standards spezifizieren eine Reihe von Funktionen / Makros für die Verwendung mit variablen Argumentlisten, den varg-Funktionen. Mit diesen Funktionen / Makros kann die aufgerufene Funktion den variablen Teil einer Argumentliste durchlaufen und die Argumente verarbeiten. Diese Funktionen sehen ungefähr so ​​aus:

%Vor%

Das Problem, das wir mit variablen Argumentlisten haben, ist, dass C keine Möglichkeit hat, das Variablenargument oder gar wie viele Argumente zu kommunizieren. Der Designer der Funktion muss also einen Mechanismus bereitstellen. Bei den C-Standard-Bibliothek-E / A-Funktionen erfolgt dies mit dem Format, das die Anzahl der Argumente angibt, die auf die Formatzeichenfolge folgen, indem für jedes Argument Formatspezifizierer angegeben werden. Und da es nichts gibt, was eine Konsistenzprüfung durchführt, können Sie am Ende eine Formatzeichenfolge erhalten, die mehr oder weniger als die tatsächlichen Argumente angibt, was entweder zu einer fehlerhaften Ausgabe oder zu einer geringeren Ausgabe als erwartet führt.

Da moderne C-Compiler einen gewissen Grad an Rückwärtskompatibilität für alten C-Quellcode haben, bedeutet das, dass Sie einige der älteren Konstrukte verwenden können und der Compiler wird es hoffentlich mit einer Warnung erlauben.

Die neuen Funktionsschnittstellenspezifikationen dienen dazu, die Wahrscheinlichkeit zu verringern, dass eine Funktion falsch verwendet wird. Daher empfehlen die neuen Standards, dass Sie die Deklaration der Funktionsschnittstelle verwenden, damit der Compiler Ihnen bei der Erkennung von Schnittstellenproblemen und falscher Variablenverwendung im Funktionsaufruf helfen kann.

Wenn Sie jedoch risikofreudig sein wollen, brauchen Sie dieses Sicherheitsnetz nicht zu benutzen. Wenn Sie möchten, können Sie einfach eine Funktion mit einer leeren Argumentliste definieren und sie flügeln.

Sie könnten auch eine Antwort finden, die ich in diese Frage zum Currying gestellt habe in C , die Variablenargumentlisten zusammen mit einer Möglichkeit verwendet, zu bestimmen, wie viele Argumente zur Verfügung gestellt werden.

    
Richard Chambers 27.02.2014 16:26
quelle

Tags und Links