webentwicklung-frage-antwort-db.com.de

C-Funktionssyntax, nach Parameterliste deklarierte Parametertypen

Ich bin relativ neu bei C. Ich bin auf eine Form von Funktionssyntax gestoßen, die ich noch nie zuvor gesehen habe, wobei 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);
}
68
John

Dies ist die alte Syntax für Parameterlisten, die noch unterstützt wird. In K & R C können Sie auch die Typdeklarationen weglassen, und sie werden standardmäßig auf int gesetzt. d.h.

main(argc, argv)
char *argv[];
{
    return 0;
}

wäre die gleiche Funktion.

58
Ferruccio

Interessant ist auch der aufrufende Konventionsunterschied von Funktionen mit und Funktionen ohne Prototyp. Betrachten Sie eine Definition im alten Stil:

void f(a)
 float a; {
 /* ... */
}

In diesem Fall lautet die aufrufende Konvention, dass alle Argumente heraufgestuft werden, bevor sie an die Funktion übergeben werden. Wenn also f eine double empfängt, der Parameter jedoch den Typ float hat (was vollkommen gültig ist), muss der Compiler Code ausgeben, der das Double vor der Ausführung des Funktionskörpers in ein Float konvertiert.

Wenn Sie einen Prototyp einschließen, führt der Compiler solche automatischen Aktionen nicht mehr aus, und alle übergebenen Daten werden wie durch Zuweisung in die Typen der Parameter 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 übergebenen Parameter von double (dem aufgerufenen Formular) in float konvertieren, da die Definition im alten Stil ist. Der Parameter wurde jedoch als Float übergeben, da die Funktion über einen Prototyp verfügt. Ihre Lösungsmöglichkeiten für die Widersprüche sind folgende:

// 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 dadurch die alte Stildefinition von vornherein beseitigt wird. Wenn solche widersprüchlichen Funktionstypen für eine Funktion in derselben Übersetzungseinheit erscheinen, wird Ihnen der Compiler normalerweise mitteilen (ist jedoch nicht erforderlich). Wenn solche Widersprüche über mehrere Übersetzungseinheiten auftreten, wird der Fehler möglicherweise nicht bemerkt und kann dazu führen, dass Fehler schwer vorhergesagt werden. Es ist am besten, diese alten Stildefinitionen zu vermeiden.

Dies ist die so Aufrufer K & R-Stil oder Old-Style Deklaration.

Beachten Sie, dass diese Deklaration signifikant von der modernen Deklaration abweicht. Die K & R-Deklaration führt kein Prototyp für die Funktion ein, was bedeutet, dass die Typen der Parameter nicht dem externen Code zugänglich gemacht werden.

10
AnT

Während die alte Syntax für die Funktionsdefinition noch funktioniert (mit Warnungen, wenn Sie Ihren Compiler fragen), werden durch deren Verwendung keine Funktionsprototypen bereitgestellt.
Ohne Funktionsprototypen überprü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, erfolgt 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
4
pmg

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 beabsichtigen, ihn Ihren Freunden aus den 80ern zu geben . hängt niemals von impliziten Typannahmen ab (wie eine andere Antwort nahelegt)

3
aviraldg

Es ist genauso, aber alte Mode. Sie haben wahrscheinlich festgestellt, dass es sich um einen alten Code handelt.

1
eyalm

Alt oder nicht, ich würde argumentieren, was alt ist und was nat .. wie die Pyramiden sind uralt, aber keiner der heute so genannten Wissenschaftler hat eine Ahnung, wie sie gemacht wurden. Rückblickend funktionieren alte Programme auch heute noch ohne Speicherverluste, aber diese "neuen" Programme neigen dazu, oftmals zu versagen. Ich sehe hier einen Trend.

Wahrscheinlich sahen sie Funktionen als Strukturen, die einen ausführbaren Körper haben. Hier sind Kenntnisse über ASM erforderlich, um das Rätsel zu lösen.

Bearbeiten, hat ein Makro gefunden, das angibt, dass Sie 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 Anwendungsbeispiel, Bibliothek ist zlib-1.2.11 .

ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));

Meine zweite Vermutung wäre also eine Funktionsüberladung, sonst hätten diese Argumente keinen Sinn. Eine konkrete Funktion und jetzt unendlich viele Funktionen mit gleichem Namen.

0
Ako