Was ist daran nützlich C
Syntax — 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 anzugeben scheint, ist die Anzahl der verwendeten Parameter und der Rückgabetyp. Ich denke, Parameter ohne Typen sind irgendwie cool, aber warum sollten Sie das zulassen und die int paranName
nach dem Funktionsdeklarator? Es ist komisch.
Ist das auch noch Standard C?
Die Frage, die Sie stellen, sind eigentlich zwei Fragen, nicht eine. Die meisten Antworten haben bisher versucht, das Ganze mit einer allgemeinen pauschalen Antwort “Das ist K&R-Stil” zu überdecken, während tatsächlich nur ein kleiner Teil davon etwas mit dem zu tun hat, was als K&R-Stil bekannt ist (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, die in function verwendet wird 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 eigentlich ist 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 weglassen können p2
).
Der zweite Teil hat wenig mit K&R-Stil zu tun. Ich verweise darauf, dass die Funktion mit “ausgetauschten” Argumenten aufgerufen werden kann, dh bei einem solchen Aufruf findet keine Parametertypprüfung statt. Das 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
das macht eine unbestimmte Anzahl von Parametern unbekannten Typs. Sie können es als nennen
foo(2, 3);
und wie
j = foo(p, -3, "hello world");
und so weiter (Sie haben die Idee);
Nur der Aufruf mit den richtigen Argumenten wird “funktionieren” (was bedeutet, dass die anderen undefiniertes Verhalten erzeugen), aber es liegt ganz bei Ihnen, für seine Korrektheit zu sorgen. Der Compiler muss die falschen nicht diagnostizieren, selbst wenn er auf magische Weise die richtigen Parametertypen und ihre Gesamtzahl kennt.
Eigentlich ist dieses Verhalten a Besonderheit der C-Sprache. Ein gefährlicher, aber dennoch ein Feature. Es erlaubt 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 mischen Sie verschiedene Funktionstypen in einem “polymorphen” Array ohne Typumwandlungen (variadische Funktionstypen können hier jedoch nicht verwendet werden). Auch hier sind die inhärenten Gefahren dieser Technik ziemlich offensichtlich (ich kann mich nicht erinnern, 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 ist Ihre func
Definition erklärt func
wie
int func();
dh es werden weder die Typen noch die Gesamtzahl der Parameter deklariert. In Ihrem ursprünglichen Beitrag sagen Sie: “… es scheint anzugeben, wie viele Parameter es verwendet …”. Formal nicht! Nach Ihrem Zwei-Parameter-K&R-Stil func
Definition können Sie immer noch anrufen func
wie
func(1, 2, 3, 4, "Hi!");
und es wird keine Einschränkungsverletzung darin geben. (Normalerweise gibt ein Qualitätscompiler eine Warnung aus).
Auch eine manchmal übersehene Tatsache ist dies
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 setzen void
in der Parameterliste
int f(void)
{
return 0;
}
Schließlich werden entgegen der landläufigen Meinung sowohl Funktionsdefinitionen im K&R-Stil als auch Nicht-Prototyp-Funktionsdeklarationen in C99 vollständig unterstützt. Ersteres ist seit C89/90 veraltet, wenn ich mich recht erinnere. C99 erfordert, dass die Funktion vor der ersten Verwendung deklariert wird, aber die Deklaration muss kein Prototyp sein. Die Verwirrung rührt offenbar von der populären terminologischen Verwechslung her: Viele Leute nennen jede Funktionsdeklaration “einen Prototyp”, während “Funktionsdeklaration” tatsächlich nicht dasselbe ist wie “Prototyp”.
Dies ist eine ziemlich alte K&R-C-Syntax (vor ANSI/ISO C). Heutzutage sollten Sie es nicht mehr verwenden (da Sie bereits den größten Nachteil bemerkt haben: Der Compiler prüft die Argumenttypen nicht für Sie). Der Argumenttyp ist tatsächlich standardmäßig auf int
in deinem beispiel.
Damals wurde diese Syntax verwendet, man fand manchmal Funktionen wie
foo(p, q)
{
return q + p;
}
das war eigentlich eine gültige definition, wie die typen für p
, q
und der Rückgabetyp von foo
standardmäßig auf int
.
Dies ist einfach eine alte Syntax, die vor der “ANSI C”-Syntax liegt, mit der Sie vielleicht besser vertraut sind. Es heißt “K&R C“, typisch.
Compiler unterstützen es natürlich, um vollständig zu sein und um mit alten Codebasen umgehen zu können.
Das ist ein Relikt aus der Zeit, als C noch keine Prototypen für Funktionen hatte. Damals wurde (glaube ich) davon ausgegangen, dass Funktionen zurückkehren int
und all seine Argumente wurden angenommen int
. Es wurde keine Überprüfung der Funktionsparameter durchgeführt.
Sie sind viel besser dran, Funktionsprototypen in der aktuellen C-Sprache zu verwenden.
Und du muss Verwenden Sie sie in C99 (C89 akzeptiert immer noch die alte Syntax).
Und C99 erfordert, dass 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.
Dies ist die ursprüngliche K&R-Syntax, bevor C 1989 standardisiert wurde. C89 führte Funktionsprototypen ein, die von C++ entlehnt wurden, und verwarf die K&R-Syntax. Es gibt keinen Grund, es in neuem Code zu verwenden (und viele Gründe, es nicht zu tun).
Es ist ein älterer Stil von Funktionsdeklarationen. Bitte sehen Sie sich diesen Link an. https://stackoverflow.com/questions/22500/what-are-the-major-differences-between-ansi-c-and-kr-c Linktext
– Leonidas Tsampros
27. Oktober 2009 um 13:04 Uhr