Objectifs. Arguments de main() Précompilateur. Compilation séparée. Makefiles



Documents pareils
Quelques éléments de compilation en C et makefiles

Cours Langage C/C++ Programmation modulaire

Le prototype de la fonction main()

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Introduction au langage C

Algorithmique et Programmation, IMA

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

UE Programmation Impérative Licence 2ème Année

Programmation système I Les entrées/sorties

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Les structures. Chapitre 3

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Programmation système de commandes en C

Programmation C. Apprendre à développer des programmes simples dans le langage C


DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

Conventions d écriture et outils de mise au point

Bases de programmation. Cours 5. Structurer les données

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

3IS - Système d'exploitation linux - Programmation système

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

Le langage C. Séance n 4

Chap III : Les tableaux

Programmation en langage C

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

Optimisation de logiciels de modélisation sur centre de calcul

Programmation système en C/C++

TP1. Outils Java Eléments de correction

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

Cours de C. Petits secrets du C & programmation avancée. Sébastien Paumier

Mon premier rpm. 7 juin Avant de commencer RPM URPMI RPMBUILD... 2

Le langage C. Introduction, guide de reference

Notes du cours 4M056 Programmation en C et C++ Vincent Lemaire et Damien Simon

Algorithmique et programmation : les bases (VBA) Corrigé

Cours Programmation Système

Brefs rappels sur la pile et le tas (Stack. / Heap) et les pointeurs

Cours d initiation à la programmation en C++ Johann Cuenin

Cours d Algorithmique et de Langage C v 3.0

Programmation en C. École Nationale Supérieure de Techniques Avancées. Pierre-Alain Fouque et David Pointcheval

Utilisation d objets : String et ArrayList

Chaîne de production d un programme

Introduction à l algorithmique et à la programmation M1102 CM n 3

Rappels Entrées -Sorties

Compression de Données - Algorithme de Huffman Document de Conception

I. Introduction aux fonctions : les fonctions standards

Introduction à la programmation Travaux pratiques: séance d introduction INFO0201-1

Arguments d un programme

Algorithmique & Langage C IUT GEII S1. Notes de cours (première partie) cours_algo_lgc1.17.odp. Licence

Programmation C. J.-F. Lalande. 15 novembre 2012

TP : Gestion d une image au format PGM

Langage Éric Guérin 5 octobre 2010

STAGE IREM 0- Premiers pas en Python

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

Cours de C/C++ par la pratique. Hugues Talbot

Langage C. Patrick Corde. 22 juin Patrick Corde ( Patrick.Corde@idris.fr ) Langage C 22 juin / 289

Outils pour la pratique

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

Support de Cours de Langage C. Christian Bac

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

L informatique en BCPST

Initiation. àl algorithmique et à la programmation. en C

Cours d introduction à l informatique. Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions

Les chaînes de caractères

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Systeme d'exploitation

Langages et Concepts de Programmation Introduction à la programmation en langage C

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

OS Réseaux et Programmation Système - C5

Structure d un programme

Notes de Cours - Programmation Pascal Ferraro

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

Construction de logiciel et packaging

TP 1. Prise en main du langage Python

Cours de programmation avancée. Le langage C. Université du Luxembourg

Cours 6 : Tubes anonymes et nommés

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Java Licence Professionnelle CISII,

SUPPORT DE COURS. Langage C

INFO-F-404 : Techniques avancées de systèmes d exploitation

Notions fondamentales du langage C# Version 1.0

INITIATION A LA PROGRAMMATION

Chapitre 10 : Logiciels

Environnements de développement (intégrés)

Projet d informatique M1BI : Compression et décompression de texte. 1 Généralités sur la compression/décompression de texte

Premiers Pas en Programmation Objet : les Classes et les Objets

I00 Éléments d architecture

Programmation impérative

Programme awk------introduction rapide

Les fichiers. Chapitre 4

Cours de C++ François Laroussinie. 2 novembre Dept. d Informatique, ENS de Cachan

Programmation en langage C d un µcontrôleur PIC à l aide du compilateur C-CCS Sommaire

Les structures de données. Rajae El Ouazzani

PROJET ALGORITHMIQUE ET PROGRAMMATION II

Généralités sur le Langage Java et éléments syntaxiques.

UE C avancé cours 1: introduction et révisions

Introduction à MATLAB R

Transcription:

du cours d aujourd hui Programmation «orientée système» LANGAGE C COMPILATION passer des arguments à son programme directives de précompilation compilation Makefile Laboratoire d Intelligence Artificielle Faculté I&C Programmation Orientée Système Langage C 1 / 54 Programmation Orientée Système Langage C 2 / 54 Mon programme dans son environnement Valeur de retour de Votre programme est exécuté par la machine dans un environnement : interpréteur de commandes / système d exploitation Que signifie cet entier retourné par? Il peut donc interagir avec eux (cf par exemple les flots). Votre programme est un processus du système, une sorte de «fonction» du système En fait, est une fonction (presque) comme les autres, qui a juste les spécificités : de toujours être appelée en premier ; de n avoir que deux prototypes possibles. C est le «statut» retourné au système d exploitation par le processus correspondant au programme. Rappel : la variable $? du Shell Choisir : la valeur 0 (ou mieux : EXIT_SUCCESS, qui est défini dans stdlib.h) si tout va bien, autre chose, s il y a une erreur (un code à vous ou alors EXIT_FAILURE). C est donc à elle de gérer les interactions avec l environnement d appel. Programmation Orientée Système Langage C 3 / 54 Programmation Orientée Système Langage C 4 / 54

(2) On a vu le prototype int main(void); Dans le prototype int main(int argc, char* argv[]) Quel est l autre prototype de? argc est un entier comptant le nombres d arguments (+1) passés au programme argv est un tableau de pointeurs sur des caractères : tableau des arguments int main(int argc, char* argv[]) argv[0] correspond au nom du programme. Ces arguments sont les paramètres donnés par l interpréteur de commandes appellant la fonction main. Exemple : passer une option «-v» et un fichier à un programme monprogramme -v fichier Exemple : monprogramme -v fichier argv[0] argv[1] argv[2] argc=3 Programmation Orientée Système Langage C 5 / 54 Programmation Orientée Système Langage C 6 / 54 Traitement des arguments de int main(int argc, char* argv[]) int erreur; erreur = traite_arguments(&argc, argv); if (erreur!= OK) return erreur; On peut distinguer 3 types d arguments obligatoires e.g. un nom de fichier : rm fichier optionnels e.g. une option d affichage : ls -l un const int défini au préalable, par exemple EXIT_SUCCESS optionnels avec arguments e.g. changer une valeur par défaut : dvips -o masortie.ps Exemple int traite_arguments(int* nb, char** argv) int required = 0; /* nb d'arguments obligatoires déjà traités */ char const * const pgm_name = argv[0]; /* le nom du programme */ ++argv; --(*nb); /* passe à l'argument suivant */ while ((*nb) > 0) /* tant qu'il y a des arguments */ if (!strcmp(argv[0], "-P")) /* option -P */ /* par exemple, avec option_p une variable globale, ou mieux un champ de structure passée en paramètre */ option_p = 1; else if (!strcmp(argv[0], "-i")) /* une option avec 1 argument : par exemple -i nom */ option_i = 1; ++argv; --(*nb); /* passe à l'argument suivant */ if (*nb == 0) /* si l'argument de l'option n'est pas là*/ fprintf(stderr, "ERREUR: pas d'argument pour l'option -i\n"); return ERREUR_I; /* une constante définie globalement */ Programmation Orientée Système Langage C 7 / 54 Programmation Orientée Système Langage C 8 / 54

else /* traite l'argument de l'option */ fait_ce_qui_faut(argv[0]); else /* traite les arguments obligatoires */ if (required >= NB_REQUIRED) fprintf(stderr, "ERREUR: je ne comprend pas l'option %s\n", argv[0]); return ERREUR_UNK; else soccupe_argument_obligatoire(argv[0]); ++required; ++argv; --(*nb); /* passe à l'argument suivant */ /* vérifie qu'on a bien eu tous les arguments obligatoires */ if (required!= NB_REQUIRED) fprintf(stderr, "ERREUR: il manque des arguments\n"); return ERREUR_LESS; return OK; d un programme C fichier source hello.c #include <stdio.h> int main(void) printf("hello World!\n"); return 0; compilateur commande : gcc hello.c -o hello fichier exécutable hello 010100001010101 001010101001110 101111001010001 Programmation Orientée Système Langage C 9 / 54 Programmation Orientée Système Langage C 10 / 54 Précompilation La compilation est, en fait, une étape un peu plus compliquée que ce que nous avons vu jusque maintenant. Le compilateur (par abus de langage) effectue en effet plusieurs opérations successives : La précompilation, dont le rôle est de substituer les macros (récriture) choisir les lignes de codes en compilation conditionnelle inclure les fichiers demandés (directive #include) la compilation proprement dite, qui produit du code assembleur l assemblage du code assembleur en code objet l édition de liens entre différents codes objets pour en faire un code exécutable (un code «chargeable», en toute rigueur). Nous ne parlerons pas du tout de la troisième étape (ni d assembleur) dans ce cours. d un programme C fichier source précompilateur gcc -E hello_e.c fichier source 2 compilateur gcc -S typedef long unsigned int size_t; fichier ASM typedef unsigned char u_char; typedef unsigned short int u_short; typedef unsigned int u_int; typedef unsigned long int u_long; typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int int16_t; typedef unsigned short int uint16_t; typedef signed int int32_t; assemblage gcc -c fichier «objet» hello.asm.lc0: main:.lfb0: éd. liens ld fichier exécutable.file "hello.c".section.rodata.string "Hello World!".text.globl main.type main, @function.cfi_startproc pushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16 movq %rsp, %rbp.cfi_def_cfa_register 6 movl $.LC0, %edi Programmation Orientée Système Langage C 11 / 54 Programmation Orientée Système Langage C 12 / 54

Macros de précompilation La commande #define, déjà rencontrée au moment des tableaux, est, en fait, un moyen (trop?) puissant de récriture de code. #define (suite) Attention! Il faut bien comprendre que cela ne fait que récrire du code avant de le passer au compilateur. En se rappelant bien cela, on évitera peut être de commettre des erreurs classiques (voir plus loin). La syntaxe de #define est la suivante : #define alias ( arguments ) séquence_à_récrire où la portion ( arguments ) est optionnelle. Par exemple #define TAILLE_MAX 12 ne fait que dire au compilateur de remplacer chaque occurrence de la chaîne TAILLE_MAX par la séquence de caractères 12. Autre exemple (avec arguments) : #define affiche_entier(x) printf("%d\n", x) Ici l expression à remplacer sera également récrite mais en récrivant également le x par la chaîne de caractères donnée entre parenthèse à affiche_entier Ainsi affiche_entier(i); sera vu par le compilateur comme printf("%d\n", i); affiche_entier(12); comme printf("%d\n", 12); et affiche_entier(affiche_entier(i)); (pourquoi pas?) comme printf("%d\n", printf("%d\n", i)); Si celle-ci a ensuite un sens pour le compilateur, tant mieux ; sinon un message d erreur intervient lors de la compilation, mais concernant la chaîne remplacée! Ce qui est parfois source de confusion. Programmation Orientée Système Langage C 13 / 54 Programmation Orientée Système Langage C 14 / 54 #define (3) #define (4) On peut passer autant d arguments à la macro que l on veut, séparés par des virgules. Qu affiche le bout de code suivant? #define mult(x,y) x*y Exemple (à améliorer) : #define mult(x,y) x*y Autre exemple, plus classique : #define max(x,y) ((x) < (y)? (y) : (x)) Note :?: est un opérateur ternaire, tel que «A? B : C» vaut B si A est non nul (i.e. «vrai») et C sinon. printf("%d\n", mult(5-5, 7-2)); Réponse : Pourquoi? Appliquez bêtement le fonctionnement de #define : il récrit! Le bout de code précédent est donc vu par le compilateur comme printf("%d\n", 5-5*7-2); c est-à-dire (en mettant plus en évidence les règles de priorités) printf("%d\n", 5-5*7-2); Programmation Orientée Système Langage C 15 / 54 Programmation Orientée Système Langage C 16 / 54

#define (suite) CONSEIL (voire règle!) : PARENTHÈSEZ les arguments de vos macros! Écrivez #define mult(x,y) ((x)*(y)) (les deux parenthèses sont nécessaires), plutôt que #define mult(x,y) x*y #define (prise de tête) Il est possible de faire considérer les arguments d une macro comme une chaîne de caractères au sens du langage C (i.e. x "x") (Écrire pour cela #x au lieu de x) ou de concaténer un argument avec les caractères voisins, en utilisant ## Note : ce dernier moyen permet d avoir un mécanisme sommaire similaire aux templates du C++ (mais à déconseiller, dans ce cas passez plutôt à C++!) Exemples : Autre conseil : N utilisez PAS de macros, à moins de très bien savoir ce que vous faites Leur utilisation contient encore d autres pièges (évaluation multiple des arguments) Préférez des fonctions ou des constantes lorsque c est possible. #define affiche(fmt,var) printf("ici, " #var "=" #fmt "\n", var) affiche(%d, i); #define coupledef(type) \ typedef struct type x; type y; couple_ ## type printf("ici, " "i" "=" "%d" "\n", i); coupledef(double); typedef struct double x; double y; couple_double; Programmation Orientée Système Langage C 17 / 54 Programmation Orientée Système Langage C 18 / 54 #define (prise de tête parfois bien pratique) Macros prédéfinies #include <stdio.h> #define SIZE 12 #define STR(X) #X #define INPUT_FMT(X) "%" STR(X) "s" LINE FILE DATE TIME STDC numéro de ligne courante dans le code source nom du fichier en train d être compilé date de la compilation heure de la compilation 1 si conformité au C standard demandée int main(void) char lu[size+1] = ""; lu[size] = '\0'; int status; status = scanf(input_fmt(size), lu); printf(">%s< (%d)\n", lu, status); return 0; Exemples d utilisation : fprintf(stderr, "Erreur ligne %d de %s : message d'erreur\n", LINE, FILE ); const char version[] = FILE " du " DATE " " TIME ; Programmation Orientée Système Langage C 19 / 54 Programmation Orientée Système Langage C 20 / 54

conditionnelle conditionnelle : Exemples La compilation conditionnelle permet de générer, avec le même code source, plusieurs programmes exécutables différents. Un exemple classique : Un exemple classique (recommandé) est de générer la version «normale» et la version «mise au point» (debug). [voir plus loin] La compilation conditionnelle se fait à l aide de l une des directives de précompilation suivante #if expression #ifdef identificateur #ifndef identificateur puis #elif ou #else, optionnels, et le tout terminé par. #ifndef M_PI #define M_PI 3.14159265358979323846 Note : la constante M_PI (et d autres qui viennent du standard Unix98 et ont aussi été disponibles en 4.4BSD) n est en toute rigueur pas définie dans le standard C (ni 89, ni 99, ni 11) :-(. Elle est souvent fournie «à bien plaire» par les compilateurs, mais est parfois supprimée si l on demande de respecter strictement le standard. Programmation Orientée Système Langage C 21 / 54 Programmation Orientée Système Langage C 22 / 54 conditionnelle : Exemples Autre exemple : #ifdef DEBUG printf("ici nous avons i=%d\n", i); Si le programme contient #define DEBUG, ou est compilé avec l option -DDEBUG (strictement équivalent), alors le printf sera exécuté. Sinon, c est rigoureusement comme si la ligne n existait pas. Troisième exemple : #ifdef DEBUG #define affiche(fmt, var) \ printf("ici, " #var "=" fmt "\n", var) #else #define affiche(fmt, var) Approche modulaire Jusqu à maintenant vos programmes étaient écrits en une seule fois, dans un seul fichier. Cette approche n est pas réaliste pour des programmes plus conséquents, qui nécessitent partage de composants, maintenance, réutilisation, On préfère une approche modulaire c est-à-dire une approche qui décompose la tâche à résoudre en sous-tâches implémentées sous la forme de modules génériques (qui pourront être réutilisés dans d autres contextes). Chaque module correspond alors à une tâche ponctuelle, à un ensemble cohérent de données, à un concept de base, etc. Programmation Orientée Système Langage C 23 / 54 Programmation Orientée Système Langage C 24 / 54

Utilité Pourquoi faire cela? Pour rendre réutilisable : éviter de réinventer la roue à chaque fois La conception d un programme doit tenir compte de deux aspects importants : la réutilisation des objets/fonctions existants : bibliothèques logicielles («libraries» en anglais) ; (les autres/passé nous/présent) la réutilisabilité des objets/fonctions nouvellement créés. (nous/présent les autres/futur) Pour maintenir plus facilement : pas besoin de tout recompiler le jour où on corrige une erreur dans une (sous--sous-)fonction Pour pouvoir développer des programmes indépendamment, c est-à-dire même si le code source n est pas disponible Distribuer des bibliothèques logicielles (morceaux de code) sans en donner les codes sources (protection intellectuelle). Remarque : vous pouvez vous-même créer vos propres bibliothèques. Conception modulaire Concrètement, cela signifie que les types, structures de données et fonctions correspondant à un «concept de base» seront regroupés dans un fichier qui leur est propre. Par exemple, on définira la structure qcm et ses fonctions dans un fichier, à part de son utilisation. séparation des déclarations des objets de leur utilisation effective (dans un ). Concrètement, cela crée donc plusieurs fichiers séparés qu il faudra regrouper («lier») en un tout pour faire un programme. Programmation Orientée Système Langage C 25 / 54 Programmation Orientée Système Langage C 26 / 54 Exemple typedef struct qcm; Différents fichiers void affiche(qcm const * question); int poser_question(qcm const * question); void affiche(qcm const * question) int poser_question(qcm const * question) int demander_nombre(int min, int max); int demander_nombre(int a, int b) La partie déclaration est la partie visible du module que l on écrit, qui va permettre son utilisation (et donc sa réutilisation). Elle est utile aux autres fichiers sources pour pouvoir y utiliser les objets déclarés. fichiers de déclaration (fichiers «headers», avec une extension.h). Ils sont inclus en début de code source via la commande #include Ils servent à la compilation des codes source en code objet. La partie définition est l implémentation du code correspondant et n est pas directement nécessaire pour l utilisateur du module. Elle peut être cachée. fichiers de définitions (codes sources, avec une extension.c) int main(void) qcm maquestion; poser_question(maquestion); Ce sont ces fichiers que l on compile pour créer du code machine (fichiers objets). Les fichiers objets sont regroupés lors de l édition de liens qui prépare l exécutable final. Programmation Orientée Système Langage C 27 / 54 Programmation Orientée Système Langage C 28 / 54

typedef : struct exemple qcm; void affiche(qcm const * question); int poser_question(qcm const * question); void affiche(qcm const * question) int poser_question(qcm const * question) La séparation des parties déclaration et définition en deux fichiers permet une compilation du programme complet : phase 1 (compilation) : production de fichiers binaires (appelés fichiers objets) correspondant à la compilation des fichiers sources (.c) contenant les parties définitions ; phase 2 (édition de liens) : production du fichier exécutable final à partir des fichiers objets et des éventuelles bibliothèques. #include "qcm.h" void affiche(qcm const * question) int poser_question(qcm const * question) qcm.c typedef struct qcm; void affiche(qcm const * question); int poser_question(qcm const * question); qcm.h Programmation Orientée Système Langage C 29 / 54 Note : pour un programme en N parties (.c), il y a N phases de compilation et 1 seule phase d édition de liens. Programmation Orientée Système Langage C 30 / 54 d un programme C compilateur fichier source commande : gcc hello.c -o hello fichier exécutable d un programme C fichier source1 fichier source2 gcc -c qcm.c -o qcm.o compilateur fichier objet1 fichier objet2 hello.c gcc -c questionnaire.c -o questionnaire.o #include <stdio.h> int main(void) printf("hello World!\n"); return 0; hello 010100001010101 001010101001110 101111001010001 En fait, gcc appelle ici l éditeur de lien ld gcc questionnaire.o qcm.o -o questionnaire édition de liens fichier exécutable Programmation Orientée Système Langage C 31 / 54 Programmation Orientée Système Langage C 32 / 54

Rôle de l édition de liens Rôle de l édition de liens (2) Les différentes composantes d un programme ayant été compilées séparément, le code compilé (ou «code objet») contient des références à des bouts de codes non connus au moment la compilation. (c est aussi vrai pour un programme contenu dans un seul fichier : il utilise toujours des bibliothèques du systèmes [ne serait-ce que la libc!] qui ont été compilées [bien] avant lui!) Un code objet, c est en fait du code partiel + des tables d adressage Il contient trois types de tables : table d exportation des objets globaux (variables ou fonctions) ; table d importation des objets référencés mais d adresse inconnue ; Le rôle de l édition de liens («linker») est précisément de construire ces liens entre bouts de codes compilés séparément : résoudre les ambiguïtés d appel table des tâches : liste des endroits dans le code où se trouvent les adresses à résoudre. Programmation Orientée Système Langage C 33 / 54 Programmation Orientée Système Langage C 34 / 54 Rôle du chargeur Mais même l édition de liens ne peut pas tout résoudre Au moment de son «chargement» (loading) pour exécution par le système d exploitation, restent encore dans le programme certains détails d adresses locales à régler. C est précisément le rôle du chargeur («loader») Le chargeur est un module du système d exploitation dont le rôle est de résoudre les dernières ambiguïtés liées au placement effectif en mémoire du programme exécutable avant de lancer son exécution proprement dite. En pratique, contrairement au compilateur et à l éditeur de liens, vous ne voyez pas explicitement ce module. Linker/Loader : exemple Reprenons notre exemple de QCM. Lors de la compilation du programme principal questionnaire.c, le compilateur ne connaît pas l adresse mémoire du code correspondant aux fonctions déclarées dans qcm.h le compilateur laisse cette partie du travail (résoudre les adresses inconnues) au linker Tables d exportation : dans qcm.o : «code» ou «variable» nom type adresse affiche code 0 en relatif poser_question code 342 en relatif (adresse de la première instruction de cette fonction par rapport à tout le code de ce module) dans questionnaire.o : nom type adresse main code 0 en relatif Programmation Orientée Système Langage C 35 / 54 Programmation Orientée Système Langage C 36 / 54

Linker/Loader : exemple (suite) Table d importation : qcm.c n en a pas (tous les objets qui y sont référencés sont connus) pour questionnaire.c : affiche, poser_question, et peut être aussi sqrt (ou autres fonctions de librairies système) Table des tâches : pour qcm.c : tous les sauts en mémoire (par exemple dus à des structures de contrôle). pour questionnaire.c : idem qcm.c plus tous les endroits où un appel à du code importé existe. Dans ce cas, les valeurs à résoudre sont exprimées en termes d entrées dans la table d importation, lesquelles seront résolues lors de l édition de lien par consultation des tables d exportation des autres codes objets. Pour finir, le chargeur modifie toutes les adresses de saut en fonction de l adresse de chargement du programme (point d entrée) (on dit que le chargeur «translate» le code) conditionnelle Exemple utile pour la compilation En toute rigueur (même si c est, en fait, redondant pour les fonctions), les fonctions prototypées dans un module mais non définies dans ce module (c est-à-dire nécessitant une édition de lien) doivent se déclarer, dans ces modules (mais pas dans le module qui les définit), comme extern Par exemple dans le qcm.h précédent, qui est prévu pour être inclus dans le fichier principal questionnaire.c, on devrait avoir extern void affiche MAIS ce fichier qcm.h contient aussi la définition de la structure qcm. Et donc pour cela (et éviter la duplication de code) on aimerait bien l inclure aussi dans qcm.c mais alors il ne faudrait pas que les prototypes des fonctions aient le mot extern Comment faire sans duplication de code? compilation conditionnelle Programmation Orientée Système Langage C 37 / 54 Programmation Orientée Système Langage C 38 / 54 conditionnelle et compilation (2) Supposons que l on ait un identificateur unique du fichier qcm.c (disons QMC_C), on peut alors écrire #ifndef QCM_C extern int poser_question( Complément sur les headers files Un même fichier.h pourrait se trouver inclus plusieurs fois dans la compilation via d autre fichier.h. Pour éviter des redéfinition multiples et garantir que le contenu d un fichier.h n est présent qu une seule fois dans une compilation donnée, on utilise le truc suivant définition d un identificateur «unique» au début du fichier Par convention c est souvent le nom du projet suivit du nom du fichier en majuscules avec des _ à la place des caractères non alphanumériques. inclusion conditionnelle du fichier (y compris la définition ci-dessus) Cela donne : #ifndef MONFICHIERAMOI_H #define MONFICHIERAMOI_H // le fichier comme d'habitude Programmation Orientée Système Langage C 39 / 54 Programmation Orientée Système Langage C 40 / 54

Complément sur les headers files (2) Les modules écrits en C peuvent également être utilisés en C++ Mais le C++ requiert que de telles fonctions soient déclarées en extern "C" Pour faire un fichier d en-tête C portable en C++, on utilisera donc une nouvelle fois la compilation conditionnelle comme suit : #ifdef cplusplus extern "C" Complément sur les headers files (résumé) Pour résumer, voici à quoi ressemble un fichier d en-tête «bien» écrit (il manque cependant encore de commentaires!) : #ifndef QCM_H #define QCM_H #ifdef cplusplus extern "C" #ifndef QCM_C #define extern_ extern #else #define extern_ // le fichier comme d'habitude typedef struct qcm; #ifdef cplusplus extern_ void affiche(qcm const * question); // #ifdef cplusplus Programmation Orientée Système Langage C 41 / 54 Programmation Orientée Système Langage C 42 / 54 Makefile (introduction) Mais quand on a un grand nombre de modules, cela devient vite fastidieux de faire toutes ces compilations et ces liens Makefile (bases) Un Makefile a une structure très simple : il est constitué d un ensemble de règles décrivant les différents modules à faire et de quoi ils dépendent («liste de dépendances»). Une règle s écrit : but: liste de dépendances pour cela il y a des moyens plus pratiques dont les Makefile Un Makefile est un fichier qui permet de construire facilement un projet en indiquant les composants et leurs dépendances. Une fois un Makefile constitué, pour réaliser l exécutable correspondant au projet il suffit de taper simplement make. Exemple : questionnaire: questionnaire.o qcm.o La règle spécifique all permet de donner la liste des «buts ultimes» que l on veut créer : all: questionnaire ou alors pour construire un programme particulier cible : make cible. Si on a des librairies système à utiliser, il faut les ajouter dans la variable LDLIBS au début du Makefile : LDLIBS = -lm Programmation Orientée Système Langage C 43 / 54 Programmation Orientée Système Langage C 44 / 54

Makefile (exemple simple) Exemple (simple) complet : LDLIBS = -lm all: questionnaire questionnaire: questionnaire.o qcm.o Makefile (suite) On n est pas obligé d utiliser les règles implicites de compilation, mais on peut, au cas par cas, spécifier exactement la/les commandes que l on souhaite exécuter pour passer des dépendances au but. Cela se fait de la façon suivante but: liste de dépendances <TAB>commande où <TAB> représente une tabulation (j insiste : pas 4 ou 8 espaces, mais 1 seul caractère <TAB>!) Remarques : 1. il n est pas nécessaire de mettre les règles simples indiquant la dépendance entre le.c et le.o correspondant (comme par exemple questionnaire.o: questionnaire.c) Ce sont des règles implicites. 2. si on veut ajouter des options au compilateur, on peut le faire avec la variable CFLAGS : CFLAGS = -ansi -g Programmation Orientée Système Langage C 45 / 54 Exemple : questionnaire: questionnaire.o qcm.o <TAB>gcc -o questionnaire questionnaire.o qcm.o On peut définir plusieurs commandes à la suite pour une même cible. Il suffit de les mettre chacune à la ligne précédée d un <TAB> Elles sont alors exécutées par make les unes après les autres (nouveau shell à chaque fois) Programmation Orientée Système Langage C 46 / 54 Makefile : variables prédéfinies Afin de faciliter l écriture des commandes dans un Makefile, un certain nombre de variables sont prédéfinies Exemples : $@ le but $? les dépendances qui ne sont plus à jour $< dépendances telles que définies par les règles par défaut $^ [GNU make] liste des dépendances $(CC) le nom du compilateur (C) $(CFLAGS) options de compilation $(LDFLAGS) options du linker $(LDLIBS) bibliothèques à ajouter Makefile : variables prédéfinies (2) Exemple de règles par défaut exprimées avec les variables prédéfinies : compilation.c.o : $(CC) -c $(CPPFLAGS) $(CFLAGS) $< édition de liens : $(CC) -o $@ $(LDFLAGS) $ˆ $(LDLIBS) Pour plus de détails : http://www.gnu.org/software/make/manual/html_node/index.html questionnaire.o: questionnaire.c qmc.h <TAB>gcc -o $@ $< Programmation Orientée Système Langage C 47 / 54 Programmation Orientée Système Langage C 48 / 54

Makefile : variables Makefile : divers (1/2) On peut également définir ses propres variables La déclaration se fait simplement avec le nom de la variable suivit de = On peut mettre des commentaires dans un Makefile Tout ce qui suit derrière un # jusqu à la fin de la ligne est considéré comme un commentaire Exemple : RUBS = *.o *~ *.bak Pour utiliser la valeur d une variable on entoure son nom de $( ) Exemple : rm $(RUBS) Si l on fait précéder la commande donnée dans une règle par @ la commande n est pas répétée à l écran lors de l exécution de make (i.e. no echo) Si l on fait précéder la commande donnée dans une règle par -, make continue l exécution même en cas d échec de cette commande Les variables peuvent être redéfinies lors de l appel : make LDLIBS=-lm monprog redéfinit la variable LDLIBS On peut générer automatiquement la liste de toutes les dépendances en utilisant l option -MM de gcc : gcc -MM *.c (on peut aussi utiliser la commande makedepend -Y *.c) Programmation Orientée Système Langage C 49 / 54 Programmation Orientée Système Langage C 50 / 54 Makefile : divers (2/2) Il existe plusieurs outils pour générer automatiquement les en fonction de la configuration de la machine. Voir par exemple : CMake, http://www.cmake.org, SCons, http://http://www.scons.org/, Jam (BJam, KJam, ) Makefile : exemple # Makefile pour le projet BIDULEMACHIN # cree par C. J. Reileppach le 11/03/2018 CC = gcc CFLAGS = -ansi -g -Wall LDFLAGS = LDLIBS = -lm RM = /bin/rm -f TARGETS = bidulemachin OBJS = *.o RUBS = $(OBJS) *~ core \#*\# the GNU Build Tools, alias «autotools» (automake, autoconf and libtool), cf http://sourceware.org/autobook/, http://autotoolset.sourceforge.net/tutorial.html les outils intégrés de développement de projets (IDE) : Code : :Blocks, KDevelop, Anjuta, NetBeans, Eclipse, all: $(TARGETS) @echo All done. clean: -@$(RM) $(RUBS) @echo Cleaned. new: clean -@$(RM) $(TARGETS) $(MAKE) all Programmation Orientée Système Langage C 51 / 54 Programmation Orientée Système Langage C 52 / 54

C : divers Prototype le plus général de main : int main(int argc, char *argv[]) argc : nombre d arguments, taille du tableau argv argv : tableau de pointeur sur des caractères : tableau des arguments. argv[0] est le nom du programme Précompilation : #define alias ( arguments ) sequence a reecrire où la portion ( arguments ) est optionnelle #if expression ou #ifdef identificateur ou #ifndef identificateur puis #elif ou #else, optionnels, et le tout terminé par. Compulation modulaire séparation des prototypes (dans les fichier.h) des définitions (dans les fichiers.c) compilation 1. Inclusion des prototypes nécessaires dans le code : #include "header.h" 2. vers un fichier "objet" (.o) : gcc -c prog.c 3. Lien entre plusieurs objets : gcc prog1.o prog2.o prog3.o -o monprog Makefile : moyen utile pour décrire les dépendances entre modules d un projet (et compiler automatiquement le projet) Syntaxe : cible: dependance <TAB>commande Programmation Orientée Système Langage C 53 / 54 Programmation Orientée Système Langage C 54 / 54