Muss Funktionsprototyp in C deklariert werden? [duplicate]

Lesezeit: 9 Minuten

Ich bin ziemlich neu in C (ich habe bereits Erfahrung mit Java, C# und etwas C++). Muss in C ein Funktionsprototyp deklariert werden oder kann der Code ohne ihn kompiliert werden? Ist es gute Programmierpraxis, dies zu tun? Oder liegt es einfach am Compiler? (Ich verwende Ubuntu 9.10 und verwende den GNU C Compiler oder gcc unter der Code::Blocks IDE)

  • Verwandte: Sind Prototypen für alle Funktionen in C89, C90 oder C99 erforderlich?

    – legends2k

    3. Februar 2014 um 8:25 Uhr

AnT steht mit Russlands Benutzer-Avatar
AnT steht zu Russland

Es ist nie erforderlich, a zu deklarieren Prototyp für eine Funktion in C, weder in “altem” C (einschließlich C89/90) noch in neuem C (C99). Es gibt jedoch einen signifikanten Unterschied zwischen C89/90 und C99 in Bezug auf Funktionsdeklarationen.

In C89/90 war es überhaupt nicht notwendig, eine Funktion zu deklarieren. Wenn die Funktion zum Zeitpunkt des Aufrufs nicht deklariert ist, “schätzt” (leitet) der Compiler die Deklaration implizit aus den Typen der beim Aufruf übergebenen Argumente und nimmt an, dass der Rückgabetyp ist int.

Zum Beispiel

int main() {
  int i = foo(5); 
  /* No declaration for `foo`, no prototype for `foo`.
     Will work in C89/90. Assumes `int foo(int)` */

  return 0;
}

int foo(int i) {
  return i;
}

In C99 muss jede Funktion, die Sie aufrufen, sein erklärt vor dem Anrufpunkt. Es ist jedoch immer noch nicht erforderlich, es mit a zu deklarieren Prototyp speziell. Eine Nicht-Prototyp-Deklaration funktioniert ebenfalls. Das bedeutet, dass in C99 die “implizit int” Die Regel funktioniert nicht mehr (in diesem Fall für abgeleitete Funktionsrückgabetypen), aber Parametertypen können immer noch aus den Argumenttypen erraten werden, wenn die Funktion ohne Prototyp deklariert wird.

Das vorherige Beispiel wird nicht in C99 kompiliert, da foo wird zum Zeitpunkt des Aufrufs nicht deklariert. Sie können jedoch eine Nicht-Prototyp-Deklaration hinzufügen

int foo(); /* Declares `foo`, but still no prototype */

int main() {
  int i = foo(5); 
  /* No prototype for `foo`, although return type is known. 
     Will work in C99. Assumes `int foo(int)` */

  return 0;
}
...

und am Ende mit gültigem C99-Code.

Trotzdem empfiehlt es sich immer, einen Prototyp für die Funktion zu deklarieren, bevor Sie sie aufrufen.

Ein zusätzlicher Hinweis: Ich habe oben gesagt, dass es nie erforderlich ist, einen Funktionsprototypen zu deklarieren. Für einige Funktionen ist es sogar eine Voraussetzung. Um a variadisch Funktion in C (printf zum Beispiel) muss die Funktion deklariert werden mit einem Prototyp vor dem Anrufpunkt. Andernfalls ist das Verhalten undefiniert. Dies gilt sowohl für C89/90 als auch für C99.

  • +1 für eine detaillierte Antwort mit allen gut erklärten Nuancen

    – legends2k

    3. Februar 2014 um 8:12 Uhr

  • “wird nicht in C99 kompiliert” — keine Compilerfehler (nur Warnungen) auf gcc und clang with -std=c99 auf meinem System. ideone kompiliert es auch

    – jfs

    22. Oktober 2017 um 17:01 Uhr


  • @jfs GCC-Dokumentation enthält Hilfe: “(…) um alle vom Standard geforderten Diagnosen zu erhalten, sollten Sie auch angeben -pedantic (oder -pedantic-errors wenn Sie möchten, dass es sich eher um Fehler als um Warnungen handelt) (…)”.

    – Przemek

    18. Juni 2018 um 13:47 Uhr

  • @Przemek, was ist dein Punkt? Versuchen Sie zu sagen, dass “-std=c99” nicht ausreicht, um zu deklarieren, dass es in c99 kompiliert wird? Vielleicht haben Sie Recht, es hängt davon ab, was jemand genau zu sagen versucht, und Ihre Interpretation kommt möglicherweise dem näher, was der Autor der Antwort mit “wird nicht in C99 kompilieren” gemeint hat.

    – jfs

    20. Juni 2018 um 14:36 ​​Uhr

  • @jfs, denn in GCC bedeutet “-std=c99” c99-Standard plus GNU-Erweiterungen. Das Problem kann möglicherweise kompiliert werden, da GNU-Erweiterungen dies zulassen. Sie müssen “-Wpedantic” hinzufügen, damit GCC alle Warnungen ausgibt, die von der strengen ISO C gefordert werden.

    – Johannes Koch

    21. April 2020 um 20:26 Uhr

Benutzeravatar von user308405
Benutzer308405

In ANSI C (d. h. C89 oder C90) müssen Sie keinen Funktionsprototypen deklarieren; Es ist jedoch eine bewährte Methode, sie zu verwenden. Der einzige Grund, warum der Standard Ihnen erlaubt, sie nicht zu verwenden, ist die Abwärtskompatibilität mit sehr altem Code.

Wenn Sie keinen Prototyp haben und eine Funktion aufrufen, leitet der Compiler einen Prototyp aus den Parametern ab, die Sie an die Funktion übergeben. Wenn Sie die Funktion später in derselben Kompilierungseinheit deklarieren, erhalten Sie einen Kompilierungsfehler, wenn sich die Signatur der Funktion von der unterscheidet, die der Compiler erraten hat.

Schlimmer noch, wenn sich die Funktion in einer anderen Kompilierungseinheit befindet, gibt es keine Möglichkeit, einen Kompilierungsfehler zu erhalten, da es ohne einen Prototyp keine Möglichkeit gibt, dies zu überprüfen. Wenn der Compiler in diesem Fall einen Fehler macht, könnten Sie ein undefiniertes Verhalten erhalten, wenn der Funktionsaufruf andere Typen auf den Stapel drückt, als die Funktion erwartet.

Die Konvention besteht darin, einen Prototyp immer in einer Header-Datei zu deklarieren, die den gleichen Namen hat wie die Quelldatei, die die Funktion enthält.

In C99 oder C11 erfordert Standard-C eine Funktionsdeklaration im Gültigkeitsbereich, bevor Sie eine Funktion aufrufen. Viele Compiler erzwingen diese Einschränkung in der Praxis nicht, es sei denn, Sie zwingen sie dazu.

  • Sie erhalten nicht unbedingt einen “Kompilierungsfehler”, wenn sich der tatsächliche Funktionstyp von dem abgeleiteten unterscheidet. Dies ist ein undefiniertes Verhalten in C, aber keine Einschränkungsverletzung.

    – AnT steht zu Russland

    4. April 2010 um 17:18 Uhr

  • Sie haben Recht, hätten genauer sein sollen, was ich meinte, war, dass die meisten Compiler eine Warnung ausgeben.

    – Benutzer308405

    4. April 2010 um 17:32 Uhr

  • In C99 benötigen Sie eine Funktionsdeklaration – obwohl ich vermute, dass es sich nicht um eine prototypische Deklaration handeln muss. C90 (C89) war da viel lockerer. Beachten Sie, dass Sie einen Prototyp im Gültigkeitsbereich benötigen, wenn die Funktion “variable Argumente” verwendet – sogar in C89/C90.

    – Jonathan Leffler

    4. April 2010 um 17:42 Uhr

  • @JeremyP: Die Compiler verzeihen standardmäßig immer noch (zu?), hauptsächlich wegen der alten Codebasen, die noch aktualisiert werden müssen. Die Compiler setzen den Buchstaben des Standards nicht durch, es sei denn, Sie zwingen ihre Hand (-Werrorzum Beispiel, und vielleicht -pedantic oder -Wold-style-definition oder -Wold-style-declaration oder -Wmissing-prototypes oder -Wstrict-prototypes oder alle (oder die meisten) der oben genannten). Ich benutze normalerweise -std=c11 und all jene außer -pedanticaber ich stelle sicher, dass POSIX oder verwandt #definesind aktiv. Ich schreibe nicht #define _GNU_SOURCE oder #define _BSD_SOURCE sehr oft.

    – Jonathan Leffler

    9. Januar 2014 um 17:45 Uhr

  • @JonathanLeffler: Ich habe einige Systeme gesehen, die andere Standardaufrufkonventionen für nicht prototypisierte Funktionen verwenden als für prototypisierte Funktionen, die Argumente annehmen, und Auch Verwenden Sie eine andere Benennung zur Verbindungszeit. Wenn eine Funktion einen Prototyp hat und nicht als Stack-basierte Argumente verwendend gekennzeichnet ist, führt der Versuch, sie ohne sichtbare Deklaration aufzurufen, zu einem Linkzeitfehler.

    – Superkatze

    28. Mai 2015 um 16:48 Uhr

Benutzeravatar von Drakosha
Drakoscha

es ist kein Muss, wenn die Funktion vor ihrer Verwendung definiert wird.

  • Was ist der Sinn, es zu definieren nach sein Nutzen?

    – Endolith

    21. Februar 2012 um 20:45 Uhr

  • Nur die logische Reihenfolge des Codes in der Datei oder die Funktion ist in einer anderen Datei definiert.

    – Drakoscha

    22. Februar 2012 um 17:37 Uhr

  • Tatsächlich ist die Definition einer Funktion im neuen Stil sowohl ein Prototyp als auch eine Deklaration. Geschieht die Definition vor jeglicher Nutzung, wäre ein weiterer Prototyp ohne Karosserie sinnlos.

    – Przemek

    18. Juni 2018 um 13:58 Uhr

Benutzeravatar von R Samuel Klatchko
R. Samuel Klatschko

Es ist nicht erforderlich, aber es ist schlechte Praxis, keine Prototypen zu verwenden.

Mit Prototypen kann der Compiler überprüfen, ob Sie die Funktion korrekt aufrufen (mit der richtigen Anzahl und Art von Parametern).

Ohne Prototypen ist Folgendes möglich:

// file1.c
void doit(double d)
{
    ....
}

int sum(int a, int b, int c)
{
    return a + b + c;
}

und das:

// file2.c

// In C, this is just a declaration and not a prototype
void doit();
int sum();

int main(int argc, char *argv[])
{
    char idea[] = "use prototypes!";

    // without the prototype, the compiler will pass a char *
    // to a function that expects a double
    doit(idea);

    // and here without a prototype the compiler allows you to
    // call a function that is expecting three argument with just
    // one argument (in the calling function, args b and c will be
    // random junk)
    return sum(argc);
}

Benutzeravatar von Raviteja
Raviteja

Wenn wir in C keinen Funktionsprototyp deklarieren und die Funktionsdefinition verwenden, gibt es kein Problem, und das Programm kompiliert und generiert die Ausgabe, wenn der Rückgabetyp der Funktion “Integer” ist. Unter allen anderen Bedingungen erscheint der Compiler-Fehler. Der Grund dafür ist, wenn wir eine Funktion aufrufen und keinen Funktionsprototyp deklarieren, generiert der Compiler einen Prototyp, der eine ganze Zahl zurückgibt, und sucht nach einer ähnlichen Funktionsdefinition. Wenn der Funktionsprototyp übereinstimmt, wird er erfolgreich kompiliert. Wenn der Rückgabetyp keine Ganzzahl ist, stimmen die Funktionsprototypen nicht überein und es wird ein Fehler generiert. Daher ist es besser, Funktionsprototypen in den Header-Dateien zu deklarieren.

Benutzeravatar von Anders Abel
Anders Abel

C erlaubt den Aufruf von Funktionen, auch wenn sie vorher nicht deklariert wurden, aber ich empfehle Ihnen dringend, für alle Funktionen einen Prototyp zu deklarieren, bevor Sie sie verwenden, damit der Compiler Sie retten kann, wenn Sie die falschen Argumente verwenden.

Benutzeravatar von cpalmer
cpalmer

Sie sollten Funktionsdeklarationen in der Header-Datei (Xh) und die Definition in der Quelldatei (Xc) ablegen. Dann können andere Dateien #include "X.h" und rufe die Funktion auf.

  • Warum ist das -1? Das sollten Sie tun.

    – cpalmer

    4. April 2010 um 17:28 Uhr

  • Kann jemand erklären, warum dies eine schlechte Idee ist, ich hatte immer den Eindruck, dass dies gängige Praxis ist? Das einzige Problem, das sich daraus ergibt, ist die zirkuläre Inklusion. Aber ansonsten, wenn Sie Ihre Includes planen, werden Sie nicht auf dieses Problem stoßen.

    – Natalie Adams

    4. April 2010 um 17:32 Uhr

  • Denn nicht alle Funktionen sollen öffentlich sein. Wenn Sie statische void foo() definiert haben nach static int bar() und bar ruft foo auf .. gut 🙂 Warum würden Sie Prototypen von Funktionen erstellen, die nicht in einem öffentlichen Header verfügbar gemacht werden? Ich bin aber nicht derjenige, der abgewählt hat.

    – Tim Post

    4. April 2010 um 18:35 Uhr


  • Ich nehme an, die Ablehnung (nicht von mir) war, weil dies die Frage nicht beantwortet.

    anon

    4. April 2010 um 18:41 Uhr

  • @Tim, bar kann foo aufrufen, da der Compiler dies bereits aus dem Prototyp kennt. Wenn dies in C nicht falsch ist, sollte es in C++ wahr sein. Können Sie ein Beispiel posten, damit wir uns vielleicht besser vorstellen können, was Sie meinen? @Neil Auch wenn es die Frage nicht direkt beantwortet, bezieht es sich auf eine “bewährte Methode”, die sich auf die Frage bezieht, die ich nicht als Notwendigkeit für eine Ablehnung sehe. Vielleicht keine positive Bewertung, aber es ist nichts, was ich entfernen lassen möchte oder unnötig ist.

    – Natalie Adams

    4. April 2010 um 22:15 Uhr

1414690cookie-checkMuss Funktionsprototyp in C deklariert werden? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy