Type et paramètres

L'entête d'une fonction est composée de son type, de son identificateur, et de la liste de ses paramètres entre parenthèses. Par exemple :
int partie_entiere(double reel)

Il existe une autre forme d'entête, datant de la première version du langage, qui ne sera pas utilisée dans ce cours :
int partie_entiere(reel)
 double reel;

Cette entête peut être précédé d'un mot clé : extern ou static :
Le résultat renvoyé par une fonction est l'argument d'une instruction return. Par exemple
return p2;
dans puissance_de_2 de puissance_de_2.c.

Une fonction qui ne renvoie pas de résultat doit être déclarée de type void. Par exemple, la fonction usage dans puissance_de_2.c.

De même, une fonction sans paramètre doit spécifier que la liste de ses paramètres est vide à l'aide du mot-clé void, sinon le compilateur laissera passer les appels contenant des paramètres. Par exemple :
int afficher_bonjour(void)
{
    printf("Bonjour !");
}

Ne pas utiliser le fait qu'une fonction qui n'est pas quittée par une instruction
return renvoie le résultat de la dernière instruction évaluée et qu'une fonction non typée explicitement est de type int. Ce type d'erreur est signalé par un avertissement.

Les paramètres sont passés par valeur. Par conséquent, une fonction ne peut changer leur valeur à l'extérieur d'elle-même. Pour pouvoir modifier une variable, il faut passer en paramètre son adresse. Cela s'appelle faire un passage par référence. Le programme fonction.c illustre ce fait :

$ fonction
entier: 1
apres appel de f: 1
apres appel de g: 2

Déclaration et définition d'une fonction

Voici la déclaration d'une fonction carre, prenant en paramètre un entier et retournant le carré de cet entier :
int carre(int i);
et voici sa définition :
int
carre(int i)
{  
    return i * i;
}

Lorsqu'une fonction est utilisée, par exemple :
k2 = carre(k);
trois cas se présentent :
  1. elle est définie après son utilisation, ou dans un autre fichier, mais déclarée avant.
    Dans ce cas, le compilateur vérifie que l'usage de la fonction est bien compatible avec sa déclaration : nombre et types des paramètres, type de la valeur de retour.
  2. elle est définie dans le même fichier, avant son utilisation.
    Dans ce cas, la définition fait également office de déclaration. Si une déclaration est aussi présente, le compilateur teste la compatibilité entre la déclaration et de la définition.
  3. elle est définie après son utilisation, ou dans un autre fichier, et non déclarée.
    Dans ce cas, le compilateur ne teste pas le type et le nombre de paramètres, et considère que cette fonction renvoie un int. Ce cas fait l'objet d'un avertissement (warning) lors d'une compilation avec l'option -Wall. Ce cas doit absolument être évité.

Usage

Les fonctions utilisées à l'extérieur du fichier où elles sont définies doivent être déclarées dans un fichier d'entête (.h). Ce fichier sera inclus (directive du pré-processeur #include) partout où elles sont utilisées, ainsi que dans le fichier où elles sont définies, de façon à garantir la cohérence entre les déclarations et les définitions.
Les fonctions utilisables uniquement à l'intérieur du fichier où elles sont définies (static) doivent néanmoins être déclarées au début du fichier, ce qui permet de déplacer leur définition sans contrainte et sans risque.