Algorithmique et Langage C
www.polytech.unice.fr/žvg/index-xidian.html
Granet Vincent - Vincent.Granet@univ-cotedazur.fr
Xi’an - Octobre 2019 - Avril 2020
Introduction
un programme C peut être réparti surplusieurs fichiers chaque fichier peut être compilé séparément
édition des liens
Structure d’un programme C
programme = ensemble de fichiers (module) fichier = liste de déclarations
déclaration = déclarations de type
déclarations de variables & définitions déclarations de fonctions & définitions déclarations d’étiquettes
directives au préprocesseur
son
176/227
Notion de Modularité
les différentes parties logiques d’un programme sont placées dans desmodules(précurseur Modula-2) reliés par desinterfaces intérêt :
outil de structuration des programmes encapsulation (données/instructions) abstraction (pour les types)
répartition des tâches entre développeurs
en C, la notion de modulen’existe pas. Toutefois, on peut assimiler un module à un fichier .c, et une interface à un fichier d’en-tête .h
son
Préfixées par static, les fonctions et les variables globales sont localesau fichier
les fonctions et les variables globales visibles danstous les fichiers doivent êtredéfiniesune seule fois. Pour les variables globales, la définition peut inclure l’initialisation
les fonctions et les variables globales utilisées dans un fichier et définies dans un autre doivent être referencéespar une
déclaration de référence préfixée parextern
utiliser un prototype complet pour les déclarations de référence à une fonction
son
178/227
Exemple : prog.c
#include "complexe.h"
i n t main(v o i d) {
Complexe c1 = initComplexe(3.2, 5.1);
Complexe c2 = initComplexe(0.05,−3.34);
ecrireComplexe(plus(c1, c2));
r e t u r n EXIT_SUCCESS;
}
son
Exemple : complexe.h
#pragma once
t y p e d e f s t r u c t {
d o u b l e reel; //la partie réelle du complexe
d o u b l e img; //la partie imaginaire du complexe
} Complexe;
e x t e r n c o n s t Complexe I;
e x t e r n Complexe initComplexe(c o n s t d o u b l e r, c o n s t d o u b l e i);
e x t e r n Complexe plus(c o n s t Complexe c1, c o n s t Complexe c2);
...
son
180/227
Exemple : complexe.c
#i n c l u d e "complexe.h"
c o n s t Complexe I = { 0, 1 };
Complexe initComplexe(c o n s t d o u b l e r, c o n s t d o u b l e i) { Complexe c = { r, i };
r e t u r n c;
}
Complexe plus(c o n s t Complexe c1, c o n s t Complexe c2) {
r e t u r n initComplexe(partieReelle(c1)+partieReelle(c2),
partieImaginaire(c1)+partieImaginaire(c2));
} ...
son
Exemple : implémentation d’une pile
/ file pile.c: implémentation d'une pile /
#d e f i n e MAX 100 t y p e d e f s t r u c t {
i n t elts[MAX], //les éléments de la pile
sp; //index du sommet de pile } PILE;
s t a t i c PILE pile; //locale au chier pile.c
i n t code_error = 0; //code d'erreur (global)
/ Rôle : renvoie 1 si la pile est pleine, et 0 sinon / s t a t i c i n t pile_pleine(v o i d)
//fonction locale { ... }
/ Rôle : dépile la pile /
/ renvoie−1, si erreur, et position le code d'erreur / i n t depiler(v o i d)
{ ... }
son 182/227
Exemple : définition de l’interface
/ fichier d'en−tête pile.h /
#pragma once
e x t e r n i n t code_error;
e x t e r n v o i d initPile(v o i d);
e x t e r n i n t empiler(i n t);
e x t e r n i n t depiler(v o i d);
...
son
Exemple : utilisation de la pile
/ fichier prog.c /
#i n c l u d e <stdlib.h>
#i n c l u d e <stdio.h>
#include "pile.h"
i n t main(v o i d) {
initPile();
....
i f (depiler() == −1)
fprintf(stderr,"erreur dépiler : %d\n",code_error);
....
r e t u r n EXIT_SUCCESS;
}
son 184/227
Exemple : structure du programme
0000000000000000000 0000000000000000000 1111111111111111111 1111111111111111111 0000000000000000000 0000000000000000000 1111111111111111111 1111111111111111111
pile.h
prog.o
pile.c
pile.o
prog libc
compilation
edition des liens prog.c
son
Exemple : compilation et édition des liens
% gcc -c -Wall pile.c
% gcc -c -Wall prog.c
% gcc -o prog prog.o pile.o
mais aussi,
% gcc -o prog prog.c pile.c
son
186/227
Quoi recompiler ?
modification d’un ou plusieurs fichiers⇒quefaut-il recompiler? il existe des liens de dépendance entre les fichiers
dans l’exemple précédent :
pile.cetprog.cdépendentdepile.h,e.g.sipile.hest modifié, il faudra recompilerpile.cetprog.c
prog.cne dépend pas depile.c,i.e.siprog.cest modifié, il sera inutile de recompilerpile.c
la commande makepermet une gestion automatique des dépendances décrites dans un fichierMake le
son
Makefile
suite de déclaration devariableset de règlesde la forme : cible : dépendances ...
commandes...
les cibles sont en général des fichiers créés par les commandes Les fichiers à (re)compiler sont fonction de ces dépendances et desdates de dernière modification
son
188/227
Makefile pour pile.c et prog.c
CC = gcc # le compilateur à utiliser CFLAGS = -pedantic -Wall # les options du compilateur LDFLAGS= # les options édition des liens SRC= pile.c prog.c # les chiers sources
OBJ= $(SRC:.c=.o) # les .o qui en découlent PROG = prog # le nom de l'exécutable .SUFFIXES: .c .o # lien entre les suf xes all: $(PROG)
$(PROG): $(OBJ)
$(CC) $(LDFLAGS) -o $@ $^ # $@ la cible
# $^ toutes les dépendances prog.o: pile.h
pile.o: pile.h
%.o: %.c
$(CC) $(CFLAGS) -c $< # $< dernière dépendance .PHONY: clean # clean n'est pas un chier clean:
rm -f *.o *~ core $(PROG)
son 189/227
Compilation avec make
$ make
gcc -pedantic -Wall -c prog.c gcc -pedantic -Wall -c pile.c gcc -o prog prog.o pile.o
$ touch pile.h ; make gcc -pedantic -Wall -c prog.c gcc -pedantic -Wall -c pile.c gcc -o prog prog.o pile.o
$ touch prog.c ; make gcc -pedantic -Wall -c prog.c gcc -o prog prog.o pile.o
$ make
make: Nothing to be done for 'all'.
$ make clean
rm -f *.o *~ core prog
son 190/227