Ich bin relativ neu in C. Ich bin auf eine Form der Funktionssyntax gestoßen, die ich noch nie gesehen habe und bei der die Parametertypen nach dieser Parameterliste definiert werden. Kann mir jemand erklären, wie es sich von der typischen C-Funktionssyntax unterscheidet?
Beispiel:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
int
deklariert und müssen daher explizit deklariert werden.Interessant ist auch der Unterschied zwischen Funktionen und Funktionen ohne Prototyp. Betrachten Sie eine alte Stildefinition:
void f(a) float a; { /* ... */ }
In diesem Fall lautet die aufrufende Konvention, dass alle Argumente heraufgestuft werden, bevor sie an die Funktion übergeben werden (z. B. wird ein
float
Argument zuerst heraufgestuftdouble
, bevor es übergeben wird). Wenn alsof
eindouble
Parameter empfangen wird , der Parameter jedoch einen Typ hatfloat
(der vollkommen gültig ist), muss der Compiler vor der Ausführung des Funktionskörpers Code ausgeben, der das Double in einen Float konvertiert.Wenn Sie einen Prototyp einfügen, führt der Compiler solche automatischen Heraufstufungen nicht mehr durch, und alle übergebenen Daten werden wie durch Zuweisung in die Parametertypen des Prototyps konvertiert. Folgendes ist also nicht legal und führt zu undefiniertem Verhalten:
void f(float a); void f(a) float a; { }
In diesem Fall würde die Definition der Funktion den übermittelten Parameter von
double
(das heraufgestufte Formular) in konvertieren ,float
da die Definition im alten Stil ist. Der Parameter wurde jedoch als Float übergeben, da die Funktion einen Prototyp hat. Zum Beispiel gibt ClangSie haben folgende Möglichkeiten, um die Widersprüche zu lösen:
// option 1 void f(double a); void f(a) float a; { } // option 2 // this declaration can be put in a header, but is redundant in this case, // since the definition exposes a prototype already if both appear in a // translation unit prior to the call. void f(float a); void f(float a) { }
Option 2 sollte bevorzugt werden, wenn Sie die Wahl haben, da die alte Stildefinition von vornherein entfernt wird. Wenn solche widersprüchlichen Funktionstypen für eine Funktion in derselben Übersetzungseinheit angezeigt werden, werden Sie normalerweise vom Compiler darüber informiert (dies ist jedoch nicht erforderlich). Wenn solche Widersprüche über mehrere Übersetzungseinheiten hinweg auftreten, bleibt der Fehler möglicherweise unbemerkt und kann zu schwer vorhersehbaren Fehlern führen. Es ist am besten, diese alten Stildefinitionen zu vermeiden.
quelle
Dies ist die so genannte Deklaration im K & R-Stil oder im alten Stil .
Beachten Sie, dass sich diese Erklärung erheblich von der modernen Erklärung unterscheidet. Die K & R-Deklaration führt keinen Prototyp für die Funktion ein, was bedeutet, dass die Parametertypen nicht dem externen Code ausgesetzt werden.
quelle
Es gibt keinen Unterschied, es ist nur die alte Syntax für Funktionsdeklarationen in C - sie wurde vor ANSI verwendet. Schreiben Sie niemals einen solchen Code, es sei denn, Sie planen, ihn Ihren Freunden aus den 80ern zu geben . Hängen Sie auch niemals von impliziten Typannahmen ab (wie eine andere Antwort zu vermuten scheint).
quelle
Während die alte Syntax für die Funktionsdefinition weiterhin funktioniert (mit Warnungen, wenn Sie Ihren Compiler fragen), bietet die Verwendung dieser Funktionen keine Funktionsprototypen.
Ohne Funktionsprototypen prüft der Compiler nicht, ob die Funktionen korrekt aufgerufen werden.
#include <stdio.h> int foo(c) int c; { return printf("%d\n", c); } int bar(x) double x; { return printf("%f\n", x); } int main(void) { foo(42); /* ok */ bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */ return 0; }
Wenn das Programm ausgeführt wird, ist die Ausgabe auf meinem Computer
$ gcc proto.c $ gcc -Wstrict-prototypes proto.c proto.c:4: warning: function declaration isn’t a prototype proto.c:10: warning: function declaration isn’t a prototype $ ./a.out 42 0.000000
quelle
Es ist genauso, aber altmodisch. Sie haben wahrscheinlich festgestellt, dass es sich um einen alten Legacy-Code handelt.
quelle
Alt oder nicht, ich würde argumentieren, was alt ist und was nicht ... wie die Pyramiden alt sind, aber keiner der heutigen sogenannten Wissenschaftler hat eine Ahnung, wie sie hergestellt wurden. Rückblickend funktionieren alte Programme noch heute ohne Speicherlecks, aber diese "neuen" Programme scheitern häufig. Ich sehe hier einen Trend.
Wahrscheinlich sahen sie Funktionen als Strukturen, die einen ausführbaren Körper haben. Kenntnisse in ASM sind hier erforderlich, um das Rätsel zu lösen.
Bearbeiten, ein Makro gefunden, das angibt, dass Sie überhaupt keine Argumentnamen angeben müssen.
#ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif
Hier ist ein Verwendungsbeispiel, Bibliothek ist zlib-1.2.11 .
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
Meine zweite Vermutung wäre also die Überladung von Funktionen, sonst hätten diese Argumente keine Verwendung. Eine konkrete Funktion und jetzt unendlich viele Funktionen mit demselben Namen.
quelle