Ich bin gerade auf den C-Code von jemandem gestoßen, bei dem ich verwirrt bin, warum er kompiliert wird. Es gibt zwei Punkte, die ich nicht verstehe.
Erstens hat der Funktionsprototyp keine Parameter im Vergleich zur tatsächlichen Funktionsdefinition. Zweitens hat der Parameter in der Funktionsdefinition keinen Typ.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
Warum funktioniert das? Ich habe es in einigen Compilern getestet und es funktioniert gut.
c
parameters
function-prototypes
function-parameter
AdmiralJonB
quelle
quelle
-Wstrict-prototypes
sowohl für dieint func()
undint main()
: xc: 3: Warnung: Funktionsdeklaration nicht ein Prototyp. Sie sollten erklären ,main()
wiemain(void)
auch.int func();
ist kompatibel mitint func(arglist) { ... }
.int main(void)
.Antworten:
Alle anderen Antworten sind richtig, aber nur zur Vervollständigung
Und noch einmal der Vollständigkeit halber. Aus C11-Spezifikation 6: 11: 6 (Seite: 179)
quelle
In C
func()
bedeutet, dass Sie eine beliebige Anzahl von Argumenten übergeben können. Wenn Sie keine Argumente wollen, müssen Sie als deklarierenfunc(void)
. Der Typ, den Sie an Ihre Funktion übergeben, wird standardmäßig verwendet, wenn nichts angegeben istint
.quelle
func(42,0x42);
(wobei alle Anrufe das Formular mit zwei Argumenten verwenden müssen).unsigned
ist nur ein anderer Name für den gleichen Typ wieunsigned int
.int func();
ist eine veraltete Funktionsdeklaration aus den Tagen, als es keinen C-Standard gab, dh aus den Tagen von K & R C (vor 1989, dem Jahr, in dem der erste "ANSI C" -Standard veröffentlicht wurde).Denken Sie daran, dass es in K & R C keine Prototypen gab und das Schlüsselwort
void
noch nicht erfunden wurde. Sie können dem Compiler lediglich den Rückgabetyp einer Funktion mitteilen . Die leere Parameterliste in K & R C bedeutet "eine nicht spezifizierte, aber feste" Anzahl von Argumenten. Behoben bedeutet, dass Sie die Funktion jedes Mal mit der gleichen Anzahl von Argumenten aufrufen müssen (im Gegensatz zu einer variadischen Funktion wieprintf
, bei der Anzahl und Typ für jeden Aufruf variieren können).Viele Compiler werden dieses Konstrukt diagnostizieren. Insbesondere
gcc -Wstrict-prototypes
erfahren Sie, dass "Funktionsdeklaration kein Prototyp ist", was genau richtig ist, da sie wie ein Prototyp aussieht (insbesondere, wenn Sie durch C ++ vergiftet sind!), dies aber nicht ist. Es ist eine alte K & R C-Rückgabetypdeklaration.Faustregel: Lassen Sie niemals eine leere Parameterlistendeklaration leer, um
int func(void)
genau zu sein. Dadurch wird die Deklaration des K & R-Rückgabetyps zu einem geeigneten C89-Prototyp. Compiler sind glücklich, Entwickler sind glücklich, statische Prüfer sind glücklich. Diejenigen, die durch ^ W ^ Wfond von C ++ irregeführt werden, können jedoch zusammenzucken, weil sie zusätzliche Zeichen eingeben müssen, wenn sie versuchen, ihre Fremdsprachenkenntnisse zu üben :-)quelle
int
.Ich würde davon ausgehen, dass jedem Build, der dies übergibt, die konfigurierte Warn- / Fehlerstufe fehlt. Es macht keinen Sinn, dies zuzulassen, um tatsächlichen Code zuzulassen.
quelle
Es ist K & R. Deklaration und Definition von Funktionen Stil. Ab C99-Norm (ISO / IEC 9899: TC3)
Abschnitt 6.7.5.3 Funktionsdeklaratoren (einschließlich Prototypen)
Abschnitt 6.11.6 Funktionsdeklaratoren
Abschnitt 6.11.7 Funktionsdefinitionen
Was der alte Stil K & R- Stil bedeutet
Beispiel:
Erklärung:
int old_style();
Definition:
quelle
C geht davon aus,
int
dass für den Funktionsrückgabetyp und die Parameterliste kein Typ angegeben ist . Nur für diese Regel sind folgende seltsame Dinge möglich.Eine Funktionsdefinition sieht so aus.
Wenn es ein Prototyp ist, schreiben Sie
Im Prototyp können Sie nur den Parametertyp angeben. Der Name der Parameter ist nicht obligatorisch. Damit
Auch wenn Sie keinen Parametertyp angeben, aber der Name
int
als Typ angenommen wird.Wenn Sie weiter gehen, funktioniert das Folgende auch.
Der Compiler geht davon aus,
int func()
wann Sie schreibenfunc()
. Aber nichtfunc()
in einen Funktionskörper stecken. Das wird ein Funktionsaufruf seinquelle
int func()
ist keine implizite Form vonint func(int)
.Wie bereits bei @Krishnabhadra erwähnt, haben alle vorherigen Antworten anderer Benutzer eine korrekte Interpretation, und ich möchte nur einige Punkte genauer analysieren.
Nehmen Sie im Old-C wie im ANSI-C als " untypisierter formaler Parameter " die Dimension Ihres Arbeitsregisters oder Ihrer Befehlstiefenfähigkeit (Schattenregister oder Befehlskumulationszyklus) in einer 8-Bit-MPU als int16 in einem 16-Bit- Parameter MPU und so wird ein int16 sein und so weiter, falls 64-Bit-Architekturen Optionen wie -m32 kompilieren können.
Obwohl es auf hoher Ebene einfacher zu implementieren erscheint, wird die Arbeit des Programmierers im Schritt des Datendyps der Steuerdimensionierung anspruchsvoller, wenn mehrere Parameter übergeben werden.
In anderen Fällen nutzten die angepassten ANSI-Compiler für einige Mikroprozessorarchitekturen einige dieser alten Funktionen, um die Verwendung des Codes zu optimieren, und zwangen die Position dieser "untypisierten formalen Parameter", innerhalb oder außerhalb des Arbeitsregisters zu arbeiten fast das gleiche mit der Verwendung von "flüchtig" und "Register".
Es ist jedoch zu beachten, dass die modernsten Compiler keinen Unterschied zwischen den beiden Arten der Parameterdeklaration machen.
Beispiele für eine Kompilierung mit gcc unter Linux:
In jedem Fall ist die lokale Angabe des Prototyps nutzlos, da kein Aufruf ohne Parameter erfolgt. Verweise auf diesen Prototyp sind nicht sinnvoll. Wenn Sie das System mit "untypisiertem Formalparameter" für einen externen Aufruf verwenden, generieren Sie einen deklarativen Prototyp-Datentyp.
So was:
quelle
int
, der im Allgemeinen entweder die Größe des Arbeitsregisters oder 16 Bit ist, je nachdem, welcher Wert kleiner ist.int
Typ zugelassen hat, der nicht alle Werte im Bereich halten konnte - 32767 bis +32767 (Hinweis -32768 ist nicht erforderlich) und kann auch allechar
Werte enthalten (dh wennchar
es sich um 16 Bit handelt, muss es entweder signiert oderint
größer sein).In Bezug auf den Parametertyp gibt es hier bereits richtige Antworten. Wenn Sie dies jedoch vom Compiler hören möchten, können Sie versuchen, einige Flags hinzuzufügen (Flags sind sowieso fast immer eine gute Idee).
Kompilieren Ihres Programms mit
gcc foo.c -Wextra
Ich bekomme:Seltsamerweise
-Wextra
fängt dies nicht fürclang
(es erkennt-Wmissing-parameter-type
aus irgendeinem Grund nicht, vielleicht für historische, die oben erwähnt wurden), aber-pedantic
tut es:Und für das Prototypproblem, wie oben noch einmal erwähnt,
int func()
bezieht es sich auf beliebige Parameter, es sei denn, Sie definieren es ausschließlich soint func(void)
, dass Sie dann die erwarteten Fehler erhalten:oder in
clang
als:quelle
Wenn die Funktionsdeklaration keine Parameter enthält, dh leer ist, werden nicht angegebene Argumente verwendet. Wenn Sie möchten, dass es keine Argumente enthält, ändern Sie es in:
quelle
Aus diesem Grund rate ich normalerweise Leuten, ihren Code zu kompilieren mit:
Diese Flags erzwingen ein paar Dinge:
Diese Flags werden standardmäßig auch in vielen Open Source-Projekten verwendet. In FreeBSD sind diese Flags beispielsweise aktiviert, wenn Sie mit WARNS = 6 in Ihrem Makefile erstellen.
quelle