Was ist an dieser C
Syntax nützlich - unter Verwendung von Funktionsdeklarationen im K & R-Stil?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Ich konnte dies in Visual Studios 2010beta schreiben
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
Ich verstehe nicht. Was ist der Sinn dieser Syntax? Ich kann schreiben:
int func (p, p2)
int p2;
{
return 0;
}
// and write
int func (p, p2)
{
return 0;
}
Das einzige, was es zu spezifizieren scheint, ist die Anzahl der verwendeten Parameter und der Rückgabetyp. Ich denke, Parameter ohne Typen sind irgendwie cool, aber warum sollte man es zulassen und int paranName
nach dem Funktionsdeklarator? Es ist komisch.
Ist das auch noch Standard C?
Antworten:
Die Frage, die Sie stellen, besteht eigentlich aus zwei Fragen, nicht aus einer. Die meisten Antworten haben bisher versucht, das Ganze mit einer generischen pauschalen Antwort "Dies ist K & R-Stil" abzudecken, während tatsächlich nur ein kleiner Teil davon etwas mit dem sogenannten K & R-Stil zu tun hat (es sei denn, Sie sehen die gesamte C-Sprache als "K & R-Stil" auf die eine oder andere Weise :)
Der erste Teil ist die seltsame Syntax in Funktion Definition
int func(p, p2) void *p; int p2; /* <- optional in C89/90, but not in C99 */ { return 0; }
Dies ist eigentlich eine Funktionsdefinition im K & R-Stil. Andere Antworten haben dies ziemlich gut abgedeckt. Und da ist eigentlich nicht viel dran. Die Syntax ist veraltet, wird aber auch in C99 noch vollständig unterstützt (mit Ausnahme der Regel "no implicit int" in C99, was bedeutet, dass Sie in C99 die Deklaration von nicht auslassen können
p2
).Der zweite Teil hat wenig mit K & R-Stil zu tun. Ich beziehe mich auf die Tatsache, dass die Funktion mit "getauschten" Argumenten aufgerufen werden kann, dh bei einem solchen Aufruf findet keine Parametertypprüfung statt. Dies hat sehr wenig mit der Definition im K & R-Stil an sich zu tun, aber es hat alles damit zu tun, dass Ihre Funktion keinen Prototyp hat. Sie sehen in C, wenn Sie eine Funktion wie diese deklarieren
int foo();
Es deklariert tatsächlich eine Funktion
foo
, die eine nicht spezifizierte Anzahl von Parametern unbekannten Typs akzeptiert . Sie können es als nennenfoo(2, 3);
und wie
j = foo(p, -3, "hello world");
ans so weiter (Sie bekommen die Idee);
Nur der Aufruf mit den richtigen Argumenten "funktioniert" (was bedeutet, dass die anderen undefiniertes Verhalten erzeugen), aber es liegt ganz bei Ihnen, die Richtigkeit sicherzustellen. Der Compiler muss die falschen nicht diagnostizieren, auch wenn er die richtigen Parametertypen und deren Gesamtzahl auf magische Weise kennt.
Tatsächlich ist dieses Verhalten ein Merkmal der C-Sprache. Eine gefährliche, aber dennoch eine Besonderheit. Es ermöglicht Ihnen, so etwas zu tun
void foo(int i); void bar(char *a, double b); void baz(void); int main() { void (*fn[])() = { foo, bar, baz }; fn[0](5); fn[1]("abc", 1.0); fn[2](); }
dh verschiedene Funktionstypen in einem "polymorphen" Array ohne Typecasts mischen (verschiedene Funktionstypen können hier jedoch nicht verwendet werden). Wiederum sind die inhärenten Gefahren dieser Technik ziemlich offensichtlich (ich erinnere mich nicht, sie jemals benutzt zu haben, aber ich kann mir vorstellen, wo sie nützlich sein kann), aber das ist schließlich C.
Schließlich das Bit, das den zweiten Teil der Antwort mit dem ersten verbindet. Wenn Sie eine Funktionsdefinition im K & R-Stil erstellen, wird kein Prototyp für die Funktion eingeführt. In Bezug auf den Funktionstyp
func
deklariert Ihre Definitionfunc
alsint func();
dh weder die Typen noch die Gesamtzahl der Parameter werden deklariert. In Ihrem ursprünglichen Beitrag sagen Sie "... es scheint anzugeben, wie viele Parameter es verwendet ...". Formal gesehen nicht! Nach Ihrer Zwei-Parameter-
func
Definition im K & R-Stil können Sie immer nochfunc
als aufrufenfunc(1, 2, 3, 4, "Hi!");
und es wird keine Einschränkungsverletzung darin geben. (Normalerweise gibt Ihnen ein Qualitätscompiler eine Warnung).
Eine manchmal übersehene Tatsache ist auch, dass
int f() { return 0; }
ist auch eine Funktionsdefinition im K & R-Stil, die keinen Prototyp einführt. Um es "modern" zu machen, müssten Sie ein explizites
void
in die Parameterliste einfügenint f(void) { return 0; }
Entgegen einer weit verbreiteten Meinung werden in C99 sowohl Funktionsdefinitionen im K & R-Stil als auch nicht prototypisierte Funktionsdeklarationen vollständig unterstützt. Ersteres ist seit C89 / 90 veraltet, wenn ich mich richtig erinnere. Für C99 muss die Funktion vor der ersten Verwendung deklariert werden, die Deklaration muss jedoch kein Prototyp sein. Die Verwirrung rührt anscheinend von der populären terminologischen Verwechslung her: Viele Leute nennen jede Funktionsdeklaration "einen Prototyp", während "Funktionsdeklaration" nicht dasselbe ist wie "Prototyp".
quelle
printf
. Funktionen ohne Prototypen können nur mit einer bestimmten festgelegten Anzahl von Argumenten korrekt aufgerufen werden, aber der Compiler weiß nicht, welches und kann nicht überprüfen (also müssen Sie das tun).supported even in C99
.C99 to C11
. :-).Dies ist eine ziemlich alte K & R C-Syntax (vor ANSI / ISO C). Heutzutage sollten Sie es nicht mehr verwenden (da Sie bereits den großen Nachteil bemerkt haben: Der Compiler überprüft die Argumenttypen nicht für Sie). Der Argumenttyp ist
int
in Ihrem Beispiel standardmäßig .Zu der Zeit, als diese Syntax verwendet wurde, fand man manchmal Funktionen wie
foo(p, q) { return q + p; }
das war eigentlich eine gültige Definition, wie die Typen für
foo
,p
undq
standardmäßigint
.quelle
Dies ist einfach eine alte Syntax, die vor der "ANSI C" -Syntax liegt, mit der Sie vielleicht besser vertraut sind. Es heißt normalerweise " K & R C ".
Compiler unterstützen es, vollständig zu sein und natürlich mit alten Codebasen umgehen zu können.
quelle
Das ist ein Relikt aus der Zeit, als C keine Prototypen für Funktionen hatte. Damals wurde angenommen, dass (ich denke) Funktionen zurückkehren
int
und alle ihre Argumente angenommen werdenint
. Die Funktionsparameter wurden nicht überprüft.Sie sind viel besser dran, Funktionsprototypen in der aktuellen C-Sprache zu verwenden.
Und Sie müssen sie in C99 verwenden (C89 akzeptiert immer noch die alte Syntax).Für C99 müssen Funktionen deklariert werden (möglicherweise ohne Prototyp). Wenn Sie eine neue Funktion von Grund auf neu schreiben, müssen Sie eine Deklaration bereitstellen. Machen Sie sie auch zu einem Prototyp: Sie verlieren nichts und erhalten zusätzliche Überprüfungen durch den Compiler.
quelle
int
Regel wurde entfernt.Dies ist die ursprüngliche K & R-Syntax, bevor C 1989 standardisiert wurde. C89 führte Funktionsprototypen ein, die aus C ++ entlehnt wurden, und veraltete die K & R-Syntax. Es gibt keinen Grund, es in neuem Code zu verwenden (und viele Gründe, dies nicht zu tun).
quelle