La question que vous posez est vraiment deux questions, pas une. La plupart des réponses ont jusqu'ici essayé de couvrir toute la question avec une couverture générique "c'est K & R style" réponse, alors qu'en fait seulement une petite partie a quelque chose à voir avec ce qui est connu comme K & R style (sauf si vous voyez la langue entière C comme « K & R style » d'une manière ou d'une autre :)
la première partie est la syntaxe étrange utilisée en fonction définition
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
celui-ci est en fait un K & Définition de la fonction de style R D'autres réponses ont couvert cela plutôt bien. Et il n'y a pas grand-chose en réalité. La syntaxe est obsolète, mais toujours entièrement supportée même en C99 (à l'exception de la règle "pas d'implicite int" dans C99, ce qui signifie que dans C99 vous ne pouvez pas omettre la déclaration de p2
).
La deuxième partie a peu à voir avec K & R-style. Je me réfère au fait que la fonction peut être appelée avec des arguments "échangés", c'est-à-dire qu'aucun contrôle de type de paramètre n'a lieu dans un tel appel. Cela a très peu à voir avec K & R-définition de style en soi, mais il a tout à voir avec votre fonction n'ayant pas de prototype. Vous voyez, en C lorsque vous déclarez une fonction comme celle
int foo();
il déclare en fait une fonction qui prend foo
un nombre indéterminé de paramètres de type inconnu. Vous pouvez l'appeler comme
foo(2, 3);
et comme
j = foo(p, -3, "hello world");
ans ainsi de suite (vous voyez l'idée); Seul l'appel avec les arguments appropriés fonctionnera (ce qui signifie que les autres produisent un comportement indéfini), mais c'est à vous de vous assurer de son exactitude. Le compilateur n'est pas obligé de diagnostiquer les incorrectes même s'il connaît magiquement les types de paramètres corrects et leur nombre total.
En fait, ce comportement est une fonctionnalité du langage C. Un dangereux, mais une caractéristique néanmoins. Il vous permet de faire quelque chose comme ça
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]();
}
à savoir mélanger les différents types de fonctions dans un tableau « polymorphes » sans typecasts (types de fonction variadique ne peuvent pas être utilisés ici même). Encore une fois, les dangers inhérents à cette technique sont assez évidents (je ne me souviens pas l'avoir jamais utilisé, mais je peux imaginer où cela peut être utile), mais c'est C après tout.
Enfin, le bit qui relie la deuxième partie de la réponse à la première. Lorsque vous définissez une définition de fonction de type R K &, elle n'introduit pas de prototype pour la fonction. En ce qui concerne le type de fonction est concerné, votre définition func
déclare func
comme
int func();
dire ni les types, ni le nombre total de paramètres sont déclarés. Dans votre message original, vous dites "... il semble spécifier combien de paramètres il utilise ...".Formellement parlant, ce n'est pas! Après votre définition à deux paramètres K & R style func
vous pouvez toujours appeler func
comme
func(1, 2, 3, 4, "Hi!");
et il n'y aura pas une violation de contrainte en elle. (Normalement, un compilateur de qualité vous donnera un avertissement).
En outre, un surplombé parfois fait que
int f()
{
return 0;
}
est aussi un K & définition de la fonction R-style qui ne présente pas un prototype. Pour le rendre « moderne » que vous auriez à mettre un void
explicite dans la liste des paramètres
int f(void)
{
return 0;
}
Enfin, contrairement à une croyance populaire, les deux K & définitions de fonction R-type et des déclarations de fonction non-prototypées sont entièrement supporté en C99. Le premier a été abandonné depuis C89/90, si je me souviens bien. C99 exige que la fonction soit déclarée avant la première utilisation, mais il n'est pas nécessaire que la déclaration soit un prototype. La confusion provient apparemment de la confusion terminologique populaire: beaucoup de gens appellent toute déclaration de fonction "un prototype", alors qu'en fait "déclaration de fonction" n'est pas la même chose que "prototype".
très bien expliqué, esp. la partie "Fonction sans prototype". –
Mais quelle est la différence entre une fonction varargs et une fonction non protégée? – Sebastian
@Sebastian Godelet varargs sont incroyablement strictes. Par exemple, appeler une fonction vararg avec un int, et l'ouvrir en octets est invalide. Ainsi est la définition d'une fonction avec seulement les paramètres vararg. – YoYoYonnY