Une déclaration:
int f();
...dit au compilateur qu'un identifiant quelconque (f
, dans ce cas) nomme une fonction, et lui indique le type de retour de la fonction - mais ne spécifie pas le nombre ou le type des paramètres que la fonction est censée recevoir.
Un prototype:
int f(int, char);
...est autrement similaire, mais spécifie également le nombre/le type des paramètres que la fonction est censée recevoir. S'il ne prend aucun paramètre, vous utilisez quelque chose comme int f(void)
pour le spécifier (car laisser les parenthèses vides est une déclaration). Une nouvelle définition de fonction de style:
int f(int a, char b) {
// do stuff here...
}
...agit également comme un prototype.
Sans un prototype en portée, le compilateur applique des promotions par défaut aux arguments avant d'appeler la fonction. Cela signifie que tout char
ou short
est promu en int
, et tout float
est promu en double
. Par conséquent, si vous déclarez (plutôt que de prototyper) une fonction, vous ne voulez pas spécifier de paramètre char
, short
ou float
- appeler une telle chose donnerait/donnera un comportement indéfini. Avec les drapeaux par défaut, le compilateur pourrait bien rejeter le code, car il n'y a pratiquement aucun moyen de l'utiliser correctement. Vous pourriez peut-être trouver un ensemble de drapeaux de compilation qui permettrait de l'accepter mais ce serait plutôt inutile, car vous ne pouvez de toute façon pas l'utiliser...