Programmer sous GNU/LINUX

Programming, Math · lab

Voir tous les documents en systèmes d'exploitation et cloud

Ecole Nationale des Sciences

de l'Informatique

TP: Programmer sous GNU/LINUX

Syst me dexploitation & Mise en Ruvre Unix

M. SELLAMI

Ce premier TP introductif la programmation en C va vous familiariser avec :

la syntaxe du langage ;

la mise en oeuvre du compilateur ;

le pr processeur cpp ;

l'utilisation d'un d bogueur/d vermineur/metteur au point ;

la compilation s par e et l'utilisation de make ;

lutilisation des biblioth ques

"

"

"

"

"

"

" divers outils relatifs au d veloppement de programmes en C.

Quelques unes des questions du pr sent sujet de TP sont inspir es d'un TP sur les sites : http://videoc.lip6.fr et

http://www.lifl.fr/~marquet/ens/cu/tpc1.html

Exercice 1

Question 1 crivez un programme qui calcule la factorielle de 10, et affiche le r sultat. On d finira une fonction

unsigned int factorielle (unsigned int n)

{

unsigned int i = 1, res = 1;

while (i <= n)

res = res * i++;

return res;

}

qui calcule la factorielle de n de fa on it rative. On placera le source de ce programme dans le fichier source

factorielle.c ;

Question 2 Compilez ce programme (le fichier source) par la commande

% gcc -g -Wall -Werror -ansi -pedantic -o factorielle factorielle.c

" on utilise le compilateur C du projet GNU, gcc ;

"

les options -ansi et -pedantic pr cisent que l'on produit des programmes C au standard ANSI C et ce de

mani re stricte. Ces options seront syst matiquement utilis es pour tous vos d veloppements, au moins dans

le cadre de ce module ;

" de m me, vous utiliserez syst matiquement les options -Wall (signaler tous les warnings) et -Werror

(consid rer les warnings comme des erreurs) ;

l'option -g du compilateur C permet de conserver des informations utiles au d vermineur ;

l'option -o permet de sp cifier le nom du fichier ex cutable, (factorielle ici, a.out par d faut).

Publicité

"

"

Si il n'y a pas d'erreur, le compilateur n'affiche rien et g n re l'ex cutable factorielle. Sinon, le compilateur affiche

la liste des erreurs qu'il a d tect es. Par exemple

% gcc -g -Wall -Werror -ansi -pedantic -o factorielle factorielle.c

factorielle.c: In function `factorielle':

factorielle.c:6: parse error before `n'

cc1: warnings being treated as errors

factorielle.c: At top level:

factorielle.c:11: warning: return-type defaults to `int'

indique que dans la fonction factorielle du fichier source factorielle.c, il y a une erreur. C'est une erreur de

syntaxe la ligne 6 (while (i n)) o il manque un op rateur entre i et n. La seconde erreur est une admonestation

(warning) la ligne 11 (main()), o le type retourn par la fonction main a t fix par d faut int. Lisez donc

toujours bien les messages d'erreurs. Ex cutez ensuite ce programme.

% factorielle

362880

Exercice 2

Question 1

1. Placez un point d'arr t avant l'appel la fonction factorielle().

2. Ex cutez alors le programme en mode pas pas (step pour entrer dans la fonction, next saute les appels de

fonction).

3. Affichez les valeurs des variables res et i (display) : leurs valeurs sont quelconques car elles n'ont encore pas

t initialis es. Les variables locales sont en effet allou es automatiquement dans la pile, qui cet instant de

l'ex cution peut contenir n'importe quoi.

4. En continuant ex cuter en mode pas pas, vous verrez les variables res et i voluer au cours des it rations

de la boucle.

Question 2 Relancez l'ex cution du programme (run) avec le m me point d'arr t. Modifier la valeur de n dans la

fonction main() :

(xxgdb) set n=12

et terminez son ex cution (cont). Le programme a bien calcul la factorielle de 12, et non pas de 10. Recommencez

avec n=13, et v rifiez que le r sultat n'est pas gal 13 fois le pr c dent. Les entiers de type int ne font bien que 32

bits sur cette machine.

Exercice 3

Le pr processeur permet de s lectionner des zones de code compiler ou ne pas compiler selon diff rentes conditions.

Il est ainsi possible de tester l'existence de macros avec les directives #ifdef/#endif, et d'inclure ou non le code

compris entre ces deux directives. On peut aussi tester la valeur d'une macro avec la directive #if/#endif. Ceci s'av re

tr s utile pour fournir des programmes pouvant tre compil s sur diff rentes architectures. Par exemple :

#if ARCH = i386

/ code pour un intel i386 /

#endif

#if ARCH = alpha

/ code pour un DEC Alpha /

#endif

Publicité

Question 1 Renommez la fonction factorielle() en factorielle_iterative(). crivez la fonction

unsigned int factorielle_recursive (unsigned int n);

qui calcule la factorielle de n de fa on r cursive. Placez les corps de ces fonctions dans une directive #ifdef/#endif

de la mani re suivante :

#ifdef RECURSIVE

unsigned int

factorielle_recursive (unsigned int n)

{

...

}

unsigned int

factorielle (unsigned int n)

{

return factorielle_recursive (n);

}

#else

unsigned int

factorielle_iterative (unsigned int n)

{

...

}

unsigned int

factorielle(unsigned int n)

{

return factorielle_iterative (n);

}

#endif

De cette mani re, si la macro RECURSIVE est d finie, seule la fonction factorielle_recursive() sera d finie, et

l'appel la fonction factorielle() sera un appel factorielle_recursive(). Sinon seule

factorielle_iterative() est d finie, et un appel factorielle sera un appel factorielle_iterative().

Question 2 La macro RECURSIVE peut tre soit d finie dans le fichier source (#define RECURSIVE), soit d finie au

moment de la compilation gr ce l'option -D nom=definition du compilateur. V rifiez le travail du pr processeur

cpp en demandant au compilateur de ne faire que la phase de pr processing :

% gcc -E -P factorielle.c | grep -v '^[ ]*$' | more

Vous voyez appara tre les d clarations de types, variables et fonctions standard, puis celles contenues dans <stdio.h>,

et enfin la d finition de factorielle_iterative(), factorielle() et main(). Recommencez en d finissant la

macro RECURSIVE :

% gcc -E -P -D RECURSIVE factorielle.c | grep -v '^[ ]*$'

C'est bien maintenant la version r cursive qui est d finie.

Question 3 Compilez la version r cursive pour tudier son comportement sous d vermineur (par exemple xxgdb, vous

pouvez pr f rer ddd) :

% gcc -D RECURSIVE -g -Wall -Werror -ansi -pedantic -o factorielle factorielle.c

% xxgdb factorielle

Publicité

1. Placez un point d'arr t avant le return de factorielle_recursive() et lancez l'ex cution (run).

2. Puis avancez de quelques appels r cursifs (step).

3. Vous pouvez examiner la pile des appels de fonctions avec la commande bt, et vous placer dans n'importe quel

cadre d'appel par la commande frame n o n est le num ro du cadre choisi ( gauche dans l'affichage fait par

bt). Par exemple,

4.

5.

6.

7.

8.

9.

(xxgdb) print n

$1 = 4

(xxgdb) frame 3

#3 0x804840d in factorielle_recursive (n=7) at factorielle.c:5

(xxgdb) print n

$2 = 7

Exercice 4

La commande make permet de d terminer automatiquement quelles parties d'un programme sont recompiler et

g n re les commandes pour ce faire. Il est tr s utile pour la compilation s par e, o un programme est constitu de

plusieurs fichiers sources.

Question 1 S parez votre programme en deux fichiers sources factorielle.c et main.c. Le premier ne contient

que les d finitions des fonctions factorielle_iterative(), factorielle_recursive() et factorielle(). Le

second ne contient que la fonction main(). Cr ez un fichier factorielle.h contenant la d claration de la fonction

factorielle :

extern unsigned int factorielle(unsigned int);

et incluez ce fichier dans main.c :

#include <stdio.h>

#include "factorielle.h"

...

Remarquez l'utilisation des doubles quotes pour indiquer au compilateur de chercher le fichier d'ent tes

factorielle.h dans le r pertoire courant en premier. Sans utiliser make, pour compiler le programme, il faut

ex cuter les commandes suivantes:

% gcc -c -Wall -Werror -ansi -pedantic factorielle.c

% gcc -c -Wall -Werror -ansi -pedantic main.c

% gcc -Wall -Werror -ansi -pedantic -o factorielle factorielle.o main.o

L'option -c de gcc permet de sp cifier au compilateur de ne pas faire l' dition de liens, et de ne g n rer que les fichiers

objets .o.

Question 2 Cr ez un fichier Makefile (ou makefile) avec le contenu suivant :

CC = gcc

CFLAGS = -Wall -Werror -ansi -pedantic

CFLAGS += -g

factorielle: factorielle.o main.o

Publicité

$(CC) $(CFLAGS) -o factorielle factorielle.o main.o

factorielle.o: factorielle.c

$(CC) -c $(CFLAGS) factorielle.c

main.o: main.c

$(CC) -c $(CFLAGS) main.c

En modifiant la date du fichier factorielle.c, et en recompilant,

% touch factorielle.c

% make

seule la compilation de factorielle.c et l' dition de liens sont ex cut es, le fichier main.c tant rest inchang .

Question 3 Dans un Makefile, on place aussi une entr e clean pour faire le m nage des fichiers interm diaire et une

entr e realclean qui ne conserve que le strict n cessaire. Ces entr es ne correspondent pas des fichiers

construire, on le pr cise make par la directive .PHONY :

CC = gcc

CFLAGS = -Wall -Werror -ansi -pedantic

CFLAGS += -g

factorielle: factorielle.o main.o

$(CC) $(CFLAGS) -o factorielle factorielle.o main.o

.PHONY: clean realclean

clean:

$(RM) factorielle.o main.o

realclean : clean

$(RM) factorielle

Partisan du moindre effort (et de la moindre erreur), on peut rassembler l'ensemble des fichiers .o dans une variable

OBJ et utiliser la variable automatique $@ :

Exercice 5

Question 1 Modifier Makefile pour pouvoir cr er une biblioth que statique libfact.a et lutiliser par le programme

factorielle.

Question 2 Modifier Makefile pour pouvoir cr er une biblioth que dynamique libfact.so et lutiliser par le programme

factorielle.

Exercice 6 Devant les difficult s et pi ges du langage C, d'autres outils sont aussi a consid rer :

" lint, dont une version moderne est LCLint (install sur le r seau enseignement et disponible

http://lclint.cs.virginia.edu), fournit nombre d'avertissements sur votre code C.

Essayez la commande lclint sur les sources crits lors de ce TP.

" gprof (GNU profiler) analyse les performances d'une ex cution d'un programme. Le programme C doit avoir t

instrument lors de la compilation (option -pg du compilateur). L'ex cution du programme produira un fichier

gmon.out. L'exploitation de ce fichier par gprof permet de visualiser l'arbre des appels des fonctions du

programme, le pourcentage de temps CPU pass dans chacune des fonctions, etc.

" nm liste les symboles pr sents dans un fichier objet (.o) ou un ex cutable. Il est ainsi possible d'identifier les

variables d finies et export es, les fonctions d finies, les fonctions utilis es sans tre d finies... dans un fichier

objet.