la programmation modulaire(2/3) |
"Diviser pour mieux régner", ce vieil adage prend toute son importance en C. Nous allons aborder ce mois-ci la compilation séparée dans laquelle le langage C excelle. Au boulot !
|
la compilation séparée et l'édition de lien |
La compilation séparée nécessite évidemment au minimum deux fichiers sources.
Pour obtenir un fichier objet (avec pour extension '.o') avec gcc il suffit de faire :
|
gcc -c nomduprogramme.c |
Nous obtiendrons alors un fichier avec pour nom "nomduprogramme.o". Quelle est la différence avec une compilation classique ? Dans cette compilation, le compilateur ne regarde que la syntaxe, et uniquement la syntaxe de notre programme. Ainsi, l'oubli d'un ';' le concernera, mais l'appel erroné d'une fonction du genre |
prinf("bonjour"); |
ne donnera pas droit a des erreurs car la syntaxe employée est bonne. Revenons un peu sur les libraires. En fait lorsqu'on ouvre un header (comme stdio.h), on voit des déclarations de fonctions mais aucune instruction. Comment une fonction comme printf fait alors pour "marcher" ? Le compilateur va chercher ces instructions dans les librairies. La librairie qui nous intéresse ici est "libc". En temps normal lorsqu'on qu'on veut inclure une libraire on compile en ajoutant dans la ligne de commande la libraire voulue. Par exemple compiler avec "gcc -lsocket serveur.c" indiquera au compilateur que certaines fonctions se trouvent définies dans la librairie socket. Par défaut libc est directement connue de gcc il n'est donc pas nécessaire de l'ajouter à la ligne de commande. Tout ceci n'explique en rien l'intérêt de créer des fichiers 'o'. ![]() principe de la compilation et de l'édition de liens Prenons un cas (presque) concret : un fichier principal que nous nommerons main.c dans lequel se trouve la fonction principale, et un fichier operation.c (ces deux fichiers se trouvent sur le cd). Dans main.c, nous mettons la fonction principale et une fonction chacune des méthodes du fichier operation.c. Etant donné que nous compilons avec l'option '-c', le compilateur n'émettra aucune erreur devant l'absence de fonctions. Dans operations.c se trouvent toutes les fonctions d'opérations (addition, multiplication.....). Pour compiler nous effectuerons ces trois opérations : gcc -c main.c (étape de compilation séparée pour main.c) gcc -c operat1.~c (étape de compilation séparée pour operation.c) gcc main.o operat~1.o -o pcteam.exe (édition de liens entre les deux fichiers objets pour donner un exécutable) Nous aboutirons ainsi à un programme (pcteam.exe) tout à fait opérationnel. Il est sûr que si nous avions fait un seul fichier main.c qui aurait contenu toutes les fonctions, la compilation aurait été plus rapide mais nous serions passés à coté de trois avantages : · la conception du programme tout d'abord : il n'y a aucun rapport entre la fonction principale main et la fonction multiplication, les mettre dans le même fichier aurait rendu le code plus complexe · ensuite la réutilisation ; si un jour nous faisons un nouveau programme qui doit utiliser certaines opérations, nous ne serons pas obligés de réécrire les fonctions d'operation.c grâce au fichier objet. Il nous suffirait de faire de faire une édition de liens entre les fichiers objets de notre programme et operations.o. Cette technique permet un travail en équipe beaucoup plus efficace. - Enfin dernier avantage, sur des codes de plusieurs milliers de lignes, il permet de localiser beaucoup plus facilement les erreurs de syntaxes. Nous verrons le mois prochain que make facilite cette tache. |
les variables globales "extern" |
Revenons un peu sur les variables globales. Comment faire en sorte qu'une variable globale déclarée dans un fichier soit accessible dans un autre fichier ? En fait le C permet de faire une déclaration de variable pour indiquer que cette variable a déjà été créé dans un autre fichier. Comment ? à l'aide du mot clé "extern". Ainsi si nous déclarons dans un fichier une variable comme ceci : |
int variable = 5; |
le fait d'écrire dans un autre fichier :
|
extern int variable; |
indiquera au compilateur qu'une variable de ce nom a été créée dans un autre fichier, mais ne réservera pas d'emplacement mémoire en plus de celui réservé par celle-ci. Bien sûr on évitera d'initialiser une variable qu'on déclare "extern". Les fonctions peuvent être déclarées extern bien que ce ne soit pas nécessaire. |
les variables globales "static" |
Il est possible de rendre confidentielle une variable globale, de telle sorte que celle-ci soit inaccessible par d'autres fichiers. On déclare alors une variable de cette manière : |
static int variable; |
Grâce à cela, il n'y aura aucune trace décelable de cette variable dans le module objet. L'avantage de déclarer une variable de la sorte est multiple : on est sûr qu'un éventuel utilisateur de notre fichier objet n'aura pas de problème s'il utilise une variable possédant le même nom (puisque cette variable "n'existe pas"), et enfin, on est sûr qu'il ne vas pas accéder à cette variable dont la valeur peut être dangereuse à changer. C'est le principe même de la sécurité en programmation orientée objet (mais nous y reviendrons). Les fonctions ici aussi peuvent être déclarées "static" pour empêcher un utilisateur de s'en servir (plus de sécurité). ![]() accessibilité des variables |
les variables "register" |
register int variable ; |
Déclarer une variable "register" indique au compilateur qu'une variable sera utilisée souvent. On lui demande donc s'il y a possibilité de la mettre dans un registre pour une rapidité accrue. Comme la variable peut-être mise dans un registre, l'opérateur unaire '&' ("adresse of") ne peut être appliqué à ce genre de variable. Evitons donc de faire un "register" sur une variable qui doit être initialisée avec un scanf (qui demande l'emplacement mémoire d'une variable). ![]() la compilation seule ne vérifie pas l'existence de fonctions… Nous verrons le mois prochain, le pré processeur, nous reviendrons sur les headers files pour une meilleure présentation de nos programmes, et nous apprendrons enfin a nous servir le l'utilitaire make. |
|
[ Précédent | Index | Suivant ] |
par Valentin BILLOTTE Dernière mise à jour: 07/02/2001 - 00:01:30 |