Jusqu'ici, nous n'avions qu'un seul fichier source dans notre projet. Ce fichier source, je vous avais demandé de l'appeler
main.c.
Plusieurs fichiers par projet
Dans la pratique, vos programmes ne seront pas tous écrits dans ce même fichier
main.c. Bien sûr, il est
possible de le faire, mais ce n'est jamais très pratique de se balader dans un fichier de 10 000 lignes (enfin, personnellement, je trouve !). C'est pour cela qu'en général on crée plusieurs fichiers par projet.
Qu'est-ce qu'un projet, déjà ?
Non, vous n'avez pas déjà oublié ? Bon : je vous le réexplique, parce qu'il est important qu'on soit bien d'accord sur ce terme.
Un projet, c'est l'ensemble des fichiers source de votre programme. Pour le moment, nos projets n'étaient composés que d'un fichier source. Regardez dans votre IDE, généralement c'est sur la gauche (fig. suivante).
Comme vous pouvez le voir à gauche sur cette capture d'écran, ce projet n'est composé que d'un fichier
main.c.
Laissez-moi maintenant vous montrer un vrai projet que vous réaliserez un peu plus loin dans le cours : un jeu de Sokoban (fig. suivante).
Comme vous le voyez, il y a plusieurs fichiers. Un vrai projet ressemblera à ça : vous verrez plusieurs fichiers dans la colonne de gauche. Vous reconnaissez dans la liste le fichier
main.c : c'est celui qui contient la fonction
main. En général dans mes programmes, je ne mets que le
main dans
main.c. Pour information, ce n'est pas du tout une obligation, chacun s'organise comme il veut. Pour bien me suivre, je vous conseille néanmoins de faire comme moi.
Mais pourquoi avoir créé plusieurs fichiers ? Et comment je sais combien de fichiers je dois créer pour mon projet ?
Ça, c'est vous qui choisissez. En général, on regroupe dans un même fichier des fonctions ayant le même thème. Ainsi, dans le fichier
editeur.c j'ai regroupé toutes les fonctions concernant l'éditeur de niveau ; dans le fichier
jeu.c, j'ai regroupé toutes les fonctions concernant le jeu lui-même, etc.
Fichiers .h et .c
Comme vous le voyez, il y a deux types de fichiers différents sur la fig. suivante.
- Les .h, appelés fichiers headers. Ces fichiers contiennent les prototypes des fonctions.
- Les .c : les fichiers source. Ces fichiers contiennent les fonctions elles-mêmes.
En général, on met donc rarement les prototypes dans les fichiers
.c comme on l'a fait tout à l'heure dans le
main.c (sauf si votre programme est tout petit).
Pour chaque fichier
.c, il y a son équivalent
.h qui contient les prototypes des fonctions. Jetez un œil plus attentif à la fig. suivante :
- il y a editeur.c (le code des fonctions) et editeur.h (les prototypes des fonctions) ;
- il y a jeu.c et jeu.h ;
- etc.
Mais comment faire pour que l'ordinateur sache que les prototypes sont dans un autre fichier que le .c ?
Il faut inclure le fichier
.h grâce à une directive de préprocesseur.
Attention, préparez-vous à comprendre beaucoup de choses d'un coup !
Comment inclure un fichier header ?… Vous savez le faire, vous l'avez déjà fait !
Regardez par exemple le début de mon fichier
jeu.c :
Code : C | #include <stdlib.h>
#include <stdio.h>
#include "jeu.h"
void jouer(SDL_Surface* ecran)
{
// ...
|
L'inclusion se fait grâce à la directive de préprocesseur
#include que vous connaissez bien maintenant. Regardez les premières lignes du code source ci-dessus :
Code : C | #include <stdlib.h>
#include <stdio.h>
#include "jeu.h" // On inclut jeu.h
|
On inclut trois fichiers
.h :
stdio,
stdlib et
jeu.
Notez une différence : les fichiers que vous avez créés et placés dans le répertoire de votre projet doivent être inclus avec des guillemets (
"jeu.h") tandis que les fichiers correspondant aux bibliothèques (qui sont généralement installés, eux, dans le répertoire de votre IDE) sont inclus entre chevrons (
<stdio.h>).
Vous utiliserez donc :
- les chevrons < > pour inclure un fichier se trouvant dans le répertoire « include » de votre IDE ;
- les guillemets " " pour inclure un fichier se trouvant dans le répertoire de votre projet (à côté des .c, généralement).
La commande
#include demande d'insérer le contenu du fichier dans le
.c. C'est donc une commande qui dit « Insère ici le fichier
jeu.h » par exemple.
Et dans le fichier
jeu.h, que trouve-t-on ?
On trouve simplement les prototypes des fonctions du fichier
jeu.c !
Code : C 1
2
3
4
5
6
7
8
9
10
11
12 | /*
jeu.h
-----
Par mateo21, pour Le Site du Zéro (www.siteduzero.com)
Rôle : prototypes des fonctions du jeu.
*/
void jouer(SDL_Surface* ecran);
void deplacerJoueur(int carte[][NB_BLOCS_HAUTEUR], SDL_Rect *pos, int direction);
void deplacerCaisse(int *premiereCase, int *secondeCase);
|
Voilà comment fonctionne un vrai projet !
Quel est l'intérêt de mettre les prototypes dans des fichiers .h ?
La raison est en fait assez simple. Quand dans votre code vous faites appel à une fonction, votre ordinateur doit déjà la connaître, savoir combien de paramètres elle prend, etc. C'est à ça que sert un prototype : c'est le mode d'emploi de la fonction pour l'ordinateur.
Tout est une question d'ordre : si vous placez vos prototypes dans des
.h (headers) inclus en haut des fichiers
.c, votre ordinateur connaîtra le mode d'emploi de toutes vos fonctions
dès le début de la lecture du fichier.
En faisant cela, vous n'aurez ainsi pas à vous soucier de l'ordre dans lequel les fonctions se trouvent dans vos fichiers
.c. Si maintenant vous faites un petit programme contenant deux ou trois fonctions, vous vous rendrez peut-être compte que les prototypes semblent facultatifs (ça marche sans). Mais ça ne durera pas longtemps ! Dès que vous aurez un peu plus de fonctions, si vous ne mettez pas vos prototypes de fonctions dans des
.h, la compilation échouera sans aucun doute.
Lorsque vous appellerez une fonction située dans fonctions.c depuis le fichier main.c, vous aurez besoin d'inclure les prototypes de fonctions.c dans main.c. Il faudra donc mettre un #include "fonctions.h" en haut de main.c.
Souvenez-vous de cette règle : à chaque fois que vous faites appel à une fonction X dans un fichier, il faut que vous ayez inclus les prototypes de cette fonction dans votre fichier. Cela permet au compilateur de vérifier si vous l'avez correctement appelée.
Comment puis-je ajouter des fichiers .c et .h à mon projet ?
Ça dépend de l'IDE que vous utilisez, mais globalement la procédure est la même :
Fichier / Nouveau / Fichier source.
Cela crée un nouveau fichier vide. Ce fichier n'est pas encore de type
.c ou
.h, il faut que vous l'enregistriez pour le dire. Enregistrez donc ce nouveau fichier (même s'il est encore vide !). On vous demandera alors quel nom vous voulez donner au fichier. C'est là que vous choisissez si c'est un
.c ou un
.h :
- si vous l'appelez fichier.c, ce sera un .c ;
- si vous l'appelez fichier.h, ce sera un .h.
C'est aussi simple que cela. Enregistrez votre fichier dans le répertoire dans lequel se trouvent les autres fichiers de votre projet (le même dossier que
main.c). Généralement, vous enregistrerez tous vos fichiers dans le même répertoire, les
.c comme les
.h.
Le dossier du projet ressemble au final à la fig. suivante. Vous y voyez des
.c et des
.h ensemble.
Votre fichier est maintenant enregistré, mais il n'est pas encore vraiment ajouté au projet !
Pour l'ajouter au projet, faites un clic droit dans la partie à gauche de l'écran (où il y a la liste des fichiers du projet) et choisissez
Add files (fig. suivante).
Une fenêtre s'ouvre et vous demande quels fichiers ajouter au projet. Sélectionnez le fichier que vous venez de créer et c'est fait. Le fichier fait maintenant partie du projet et apparaît dans la liste à gauche !
Les include des bibliothèques standard
Une question devrait vous trotter dans la tête…
Si on inclut les fichiers
stdio.h et
stdlib.h, c'est donc qu'ils existent quelque part et qu'on peut aller les chercher, non ?
Oui, bien sûr !
Ils sont normalement installés là où se trouve votre IDE. Dans mon cas sous Code::Blocks, je les trouve là :
C:\Program Files\CodeBlocks\MinGW\include
Il faut généralement chercher un dossier
include.
Là-dedans, vous allez trouver de très nombreux fichiers. Ce sont des headers (
.h) des bibliothèques standard, c'est-à-dire des bibliothèques disponibles partout (que ce soit sous Windows, Mac, Linux…). Vous y retrouverez donc
stdio.h et
stdlib.h, entre autres.
Vous pouvez les ouvrir si vous voulez, mais ça risque de piquer un peu les yeux. En effet, c'est un peu compliqué (il y a pas mal de choses qu'on n'a pas encore vues, notamment certaines directives de préprocesseur). Si vous cherchez bien, vous verrez que ce fichier est rempli de prototypes de fonctions standard, comme
printf par exemple.
Ok, je sais maintenant où se trouvent les prototypes des fonctions standard. Mais comment pourrais-je voir le code source de ces fonctions ? Où sont les .c ?
Vous ne les avez pas ! En fait, les fichiers
.c sont déjà compilés (en code binaire, c'est-à-dire en code machine). Il est donc totalement impossible de les lire.
Vous pouvez retrouver les fichiers compilés dans un répertoire appelé
lib (c'est l'abréviation de
library qui signifie « bibliothèque » en français). Chez moi, on peut les trouver dans le répertoire :
C:\Program Files\CodeBlocks\MinGW\lib
Les fichiers compilés des bibliothèques ont l'extension
.a sous Code::Blocks (qui utilise le compilateur appelé
mingw) et ont l'extension
.lib sous Visual C++ (qui utilise le compilateur
Visual). N'essayez pas de les lire : ce n'est absolument pas comestible pour un humain.
En résumé, dans vos fichiers
.c, vous incluez les
.h des bibliothèques standard pour pouvoir utiliser des fonctions standard comme
printf. Votre ordinateur a ainsi les prototypes sous les yeux et peut vérifier si vous appelez les fonctions correctement, par exemple que vous n'oubliez pas de paramètres.