ITC34 - Algorithmique et programmation Partie C / C++ Introduction Petite introduction Benoît DARTIES 1 [email protected] 2 Introduction Introduction Qu’est-ce que le C++ ? Qu’est-ce que le C ? ‣ Langage de programmation impératif - code écrit selon une suite d’instructions élémentaires - quatre type d’instructions principales ➡ assignation ➡ branchement conditionnel ➡ branchement sans condition ➡ bouclage - conçu pour la programmation système UNIX ITC34 - Partie C / C++ 3 Benoît Darties ‣ langage de programmation offrant de multiples paradigmes : - programmation impérative - programmation orientée objet - programmation générique - ... ‣ considéré comme le petit frère du C ‣ apporte de nouveaux éléments par rapport au C - objets - fonctions virtuelles - surcharge des opérateurs et des fonctions - références - gestion de flux d’entrée / sortie - ... ITC34 - Partie C / C++ Histoire du langage C Benoît Darties Histoire du langage C 1989, Ratification du standard : ANSI X3.159-1989 1972, Naissance du C ‣ ANSI C, Standard C ou encore C89 ‣ Développé par Dennis M. Ritchie, laboratoire Bell ‣ Objectif : développer une version portable d’UNIX ‣ Inspiré du langage B (1970, Ken Tompson) 1990, Adoption par l’ISO du standard ANSI ‣ International Organisation for Standardization ‣ Norme ISO/IEC 9899:1990 ‣ C90 (identique C89) 1978, définition officielle ‣ par Brian W. Kernighan & Dennis M. Ritchie ‣ livre «The C programming language», le K&R-C 1999 : Révision du standard 1983 : nouveau standard ‣ besoin d’une référence, pour répondre aux problèmes de compatibilité ‣ Standardisation ANSI-C (Américan National Standards Institute) ‣ Publication dans la seconde édition du K&R-C (1988) ITC34 - Partie C / C++ 4 5 Benoît Darties ‣ Norme ISO/IEC 9899:1990 ‣ C99 ‣ Ajout des fonctions inline, types de données, ... 2007 : réflexions sur une évolution du standard : C1X ITC34 - Partie C / C++ 6 Benoît Darties Histoire du langage C++ Histoire du langage C++ 1985, première référence 1979, Pendant ce temps ... ‣ livre «The C++ programming language» ‣ pas encore de standard officiel ‣ Bjarne Stroustrup travaille sur l’ajout de classes au C - encapsulation de données - classes dérivées - typage fort - fonctions inline (repris dans C) 1989, seconde version de C++ ‣ héritage multiple ‣ classes abstraites ‣ ... 1983, C++ adopté comme nom officiel ‣ ajout de fonctionnalités supplémentaires - fonctions virtuelles - surcharge d’opérateurs - références - constantes (repris dans C) - commentaires de fin de lignes // (repris dans C) - ... ITC34 - Partie C / C++ 1990, «The annotated C++ Reference Manual» (ARM) ‣ bases pour le futur standard 1998, Standardisation (ISO/CEI 14882:1998) ‣ Version corrigée en 2003 (ISO/CEI 14882:2003) Benoît Darties 7 Popularité des langages de programmation Position Aug 2009 Delta in Position 1 1 = Java 17.994% -1.53% A 2 2 = C 17.866% +0.65% A 3 3 = C++ 9.658% -0.84% A 4 4 = PHP 9.180% -0.21% A 5 5 = (Visual) Basic 5.413% -3.07% A 6 7 + C# 4.986% +0.54% A 7 6 - Python 4.223% -0.27% A 8 8 = Perl 3.427% -0.60% A 9 19 ++++++++++ Objective-C 3.150% +2.54% A 10 11 + Delphi 2.428% +0.09% A 11 9 -- JavaScript 2.401% -0.41% A 12 10 -- Ruby 1.979% -0.51% A 13 12 - PL/SQL 0.757% -0.23% A 14 13 - SAS 0.715% -0.10% A 15 20 +++++ MATLAB 0.627% +0.07% B 16 18 ++ Lisp/Scheme/ 0.626% 0.00% B 17 16 - Pascal 0.622% -0.05% B 18 15 --- ABAP 0.616% -0.12% B 19 14 ----- RPG (OS/400) 0.606% -0.15% B 20 - ++++++++++ Go 0.603% 0.00% B ITC34 - Partie C / C++ Jul 2010 / Jul 2009 9 8 Benoît Darties Popularité des langages de programmation Position Aug 2010 Lanugage ITC34 - Partie C / C++ Status Benoît Darties ITC34 - Partie C / C++ Ne pas confondre C et C++ ! 10 Benoît Darties Organisation de ce cours Partie C Langages très proches ‣ s’inspirent mutuellement ‣ fortes interactions : - Compilation d’un programme C avec un compilateur C++ - Utilisation de librairies statiques développées en C++ dans du C - ... ‣ mais doivent être considérés comme des langages séparés ! ITC34 - Partie C / C++ 11 Benoît Darties ‣ Bases du langage ‣ Compilation ‣ Gestion de la mémoire - mise en application sur le langage C - fonctionnement étendu au C++ (non présenté) Partie C++ ‣ Ajouts / modifications en langage impératif par rapport au C++ - Surcharge de fonctions, d’opérateurs .. - Gestion des flux ‣ Programmation orientée objets ‣ Librairies C++ ITC34 - Partie C / C++ 12 Benoît Darties Composition du langage C Six groupes de composants élémentaires : les identificateurs les mots-clé les constantes les chaînes de caractères les opérateurs les signes de ponctuation (éventuellement les commentaires) Bases du langage C ITC34 - Partie C / C++ 13 Benoît Darties 14 Les identificateurs Les mots-clé Rôle d’un identificateur ‣ Donner un rôle à une entité du programme ‣ Peut désigner : - un nom de variable - un nom de fonction - un type - .... mots réservés pour le langage C ‣ ne peuvent être utilisés comme identificateurs ‣ ANSI C compte 32 mots-clé ‣ différentes utilités Composition : suite de caractères ‣ ‣ ‣ ‣ ‣ lettres majuscules / minuscules non accentuées chiffres caractère «underscore» _ ne peut commencer par un chiffre respect de la casse : différenciation des majuscules / minuscules ITC34 - Partie C / C++ 15 Benoît Darties auto const double float int short struct unsigned break continue else for long signed switch void case default enum goto register sizeof typedef volatile char do extern if return static union while ITC34 - Partie C / C++ Structure d’un programme C 16 Benoît Darties Structure d’un programme C Un programme C : ‣ ‣ ‣ ‣ manipule des variables nommées par un identificateur sur lesquelles il effectue des opérations utilisant des opérateurs ces opérations sont décrites par des instructions ‣ suite d’instructions encadrée par des crochets ouvrant et fermant ‣ inclusion des blocs d’instructions possible Une variable : Une instruction : ‣ est une expression : suite de composants syntaxiquement correct ‣ suivie d’un point virgule ‣ a pour objet le résultat d’une action décrite par l’expression - affectation : associer une valeur à un variable - comparaison : comparaison de valeurs - opération mathématique ou logique : calcul d’une valeur - branchement : saut vers une instruction non consécutive - ... ITC34 - Partie C / C++ bloc d’instruction : 17 Benoît Darties ‣ ‣ ‣ ‣ espace mémoire fini identifiée par un identificateur capable de contenir une valeur possède un type : int, float, char, ... - nécessite d’être déclarée avant utilisation ‣ portée généralement limitée au bloc d’instruction dans lequel elle est définie ITC34 - Partie C / C++ 18 Benoît Darties Structure d’un programme C Types de données Squelette d’un programme C Types de données [directives du préprocesseur] ‣ Le langage C est un langage typé ‣ toute variable, fonction, constante est typée ‣ Un type définit : - la façon dont l’élément est représenté en mémoire - la taille occupée par l’élément - les valeurs que peut prendre l’élément (=domaine) - les opérations autorisées sur ce dernier ‣ Deux familles de types : - type primitifs - types composés (abordés plus loin) [déclaration de variables externes] [fonctions secondaires] int main() { // bloc d’instructions du main [variables internes] [instructions] } ITC34 - Partie C / C++ Benoît Darties 19 ITC34 - Partie C / C++ Types de données 20 Benoît Darties Représentation des caractères Relation entre type, taille, encodage, signification Types représentant les caractères ‣ espace mémoire de taille n bits : mot binaire Bit de poids le + fort 1 0 1 0 1 0 0 1 1 0 0 1 0 0 1 0 Bit de poids le + faible ‣ 2^n mot binaires possibles, chacun représente une valeur valeur binaire sur espace mémoire taille 16 bits valeur décimale 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 3 ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 0 0 1 1 0 0 1 0 1 1 1 0 0 0 1 1 26055 ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 65535 Signification Dépend du type ! entier ? valeur négative ? réel ? caractère ? mot ? autre ? ‣ ‣ ‣ ‣ utilisés pour représenter des caractères mot clé : char objet élémentaire du langage C taille : 1 octet (la plupart du temps), soit 256 possibilités - chaque valeur est associée à un caractère - correspondance selon le jeu de caractères de la machine utilisée ➡ Généralement jeu de caractères ISO 8859 (8 bits) ➡ Valeurs 0 à 127 : table ASCII (codée sur 7 bits) ➡ Valeurs 128 à 255 : caractères propre aux différentes langues ➡ En Europe occidentale : ISO 8859-1 (ISO-LATIN-1) ‣ une variable de type char est un mot binaire d’un octet auquel est associé un caractère ! (par l'intermédiaire d’une valeur décimale) taille : dépend du type utilisé ITC34 - Partie C / C++ 21 Benoît Darties ITC34 - Partie C / C++ Représentation des entiers Attribut de précision : ‣ utilisés pour représenter des valeurs entières - on ne peut pas représenter tous les entiers ! - impossible de représenter tous les éléments d’une quantité infinie ‣ mot clé : int - peut-être précédé d’un attribut de précision : short ou long - et/ou d’un attribut de représentation : unsigned ‣ mot clé : char - peut être précédé d’un attribut de représentation : unsigned 23 Benoît Darties Représentation des entiers Types représentant les entiers ITC34 - Partie C / C++ 22 Benoît Darties ‣ short, long , (long long depuis C99, non ANSI) ‣ Modifie le nombre d’octets alloués à la variable Encodage du signe des entiers : ‣ bit de poids le plus fort à 0 pour les entiers positifs ‣ attribut unsigned - utilisation du bit de poids le plus fort pour l’encodage du nombre - encodage d’entiers positifs ou nul seulement - valeur max deux fois plus grande ITC34 - Partie C / C++ 24 Benoît Darties Représentation des entiers Représentation des entiers Tableau des types de données pour entiers (C99, proc. 32 bits) Type Signification Taille (octet) Plage de valeurs char Caractère 1 unsigned char Caractère non signé 1 0 à 255 short int Entier court 2 -32768 à 32767 unsigned short int Entier court non signé 2 int Entier 4 unsigned int Entier non signé 4 long int unsigned long int Entier long Entier long non signé 4 2 long long int Entier long long 8 unsigned long long int Entier long long non signé ITC34 - Partie C / C++ 8 -128 à 127 0 à 65535 -32768 à 32767 -2147483648 à 2147483647 0 à 65535 0 à 4294967295 -2 147 483 648 à 2 147 483 647 0 à 4 294 967 295 –9,223,372,036,854,775,808 à 9,223,372,036,854,775,807 0 à 18,446,744,073,709,551,615 Benoît Darties 25 Conséquences : entier a; debut a <- 1; tant que (a > 0) faire a<- a + 1; fin tant que fin int main() { int a; a=1; while (a > 0) { a = a+1; } } Algorithme de boucle infinie Implémentation en C ‣ L’algorithme ne s’arrête jamais (exécution infinie) ‣ Le programme s’arrêtera au bout d’un certain temps - ceci quel que soit le type de la variable a - type : retarde la fin d’exécution ITC34 - Partie C / C++ Représentation des entiers Benoît Darties 26 Représentation des entiers Incrémentation d’une variable dont la valeur est maximum ‣ Integer Overflow ‣ Résultat obtenu dépendant du type (donc de la représentation) - Type non signé (mot clé unsigned ) - Type signé - Problèmes dans tous les cas Exemple : pacman ‣ ‣ ‣ ‣ ‣ ‣ ‣ ‣ ‣ Benoît Darties 27 Représentation des entiers négatifs Approche naïve : méthode Sign-and-Magnitude Décimal Binaire Décimal 00000000 0 10000000 -0 00000101 5 10000101 -5 01000001 65 11000001 -65 01111111 127 11111111 -127 Représentation sur type de taille 1 octet ‣ Inconvénients : - double représentation du 0 - opérations arithmétiques compliquées 29 ITC34 - Partie C / C++ Benoît Darties 28 Représentation des entiers négatifs ‣ Nombre positif codé sur n-1 bits ‣ Pour obtenir le négatif : inversion des bits Binaire ITC34 - Partie C / C++ Bit de poids fort à 0 pour les entiers positifs Valeur Max atteinte lorsque représentation binaire : 0111...1111 Valeur numérique de 1000...0000 jusqu’à 1111...1111 ? Comment sont représentés les entiers négatifs ??? Pourquoi peut-on représenter un négatif de plus qu’un positif ?? Complément-à-un ‣ n-1 bits de poids faibles : code un nombre ‣ 1 bit de poids le plus fort : code le signe - 0 : nombre positif - 1 : nombre négatif Représentation sur type de taille 1 octet ‣ Le poids de chaque bit correspond à une puissance de deux ‣ Valeur max atteinte lorsque représentation binaire : 1111...1111 ‣ incrémentation : 10000 ... 0000 - bit tout à gauche inexistant - réduction au nombre 0000...0000 Représentation des valeurs entières sur type signé Numéro de level codé sur 1 octet 256 possibilités Levels 0 à 255 OK Level 256 : problèmes d’affichage ITC34 - Partie C / C++ Représentation des valeurs entières sur type non signé : Benoît Darties Binaire Décimal Binaire Décimal 00000000 0 11111111 -0 00000101 5 11111010 -5 01000001 65 10111110 -65 01111111 127 10000000 -127 Représentation sur type de taille 1 octet Représentation sur type de taille 1 octet ‣ Avantages : - certaines opérations mathématiques sont facilités - exemple : addition ‣ Inconvénients : - double représentation du 0 ITC34 - Partie C / C++ 30 Benoît Darties Représentation des entiers négatifs Représentation des entiers négatifs Complément-à-deux Excess-N ‣ Nombre positif codé sur n-1 bits ‣ Pour obtenir le négatif : inversion des bits, et ajout de 1 ‣ Représentation d’un entier en mode non signé. ‣ Soustraction de la valeur N Binaire Décimal Binaire Décimal 00000000 0 00000000 -0 00000101 5 11111011 -5 Binaire Décimal Binaire Décimal 01000001 65 10111111 -65 00000000 -127 10000000 1 01111111 127 10000001 -127 00000101 -126 11111011 2 01000001 -1 10111111 127 01111111 0 10000001 128 Représentation sur type de taille 1 octet ‣ Exemple : Excess-127 sur 8 bits Représentation sur type de taille 1 octet ‣ Avantages : - certaines opérations mathématiques sont facilités - exemple : addition - représentation unique du 0 ITC34 - Partie C / C++ Représentation sur type de taille 1 octet ‣ Avantages : - certaines opérations mathématiques sont facilités - représentation unique du 0 Benoît Darties 31 ITC34 - Partie C / C++ Représentation des réels Benoît Darties Représentation des nombres flottants : On ne peut représenter tous les nombres réels Approximation des nombres ET des opérations Norme IEEE 754 Types float, double, long double ‣ Elements utilisés : - un signe S : 0 ou 1 - un exposant E - une mantisse M - deux constantes Exp1 et Exp2 Quelques caractéristiques : ‣ Zero positif et négatif ‣ Valeur spéciale : - NaN : Not A Number - Positive et Negative Infinite ‣ Toutes les valeurs entières représentées dans l’intervalle de définition ‣ Résultats des opérations : peut être approximatif ITC34 - Partie C / C++ 32 Représentation des réels Représentation des nombres réels ‣ ‣ ‣ ‣ Représentation sur type de taille 1 octet Benoît Darties 33 Représentation des entiers (-1)^S x 1.M x 2^(E - Exp1) ‣ Nombres normalisés : ‣ Nombres dénormalisés (E=0) : (-1)^S x 0.M x 2^(E - Exp2) ITC34 - Partie C / C++ 34 Benoît Darties Les constantes et chaînes de caractères Tableau des types de données pour flottants Taille (octets) Mantisse (bits) Exposant (bits) Exp1 Exp2 float 4 23 8 127 126 3.4*10^-38 à 3.4*10^38 double 8 52 11 1023 1022 1.7*10^-308 à 1.7*10^308 long double 10 64 15 16283 16382 3.4*10^-4932 à 3.4*10^4932 Type Plage de valeurs Arithmétique des flottants -00 0 ITC34 - Partie C / C++ 0 1 +00 35 1 Benoît Darties Les constantes ‣ valeurs qui apparaissent littéralement dans un code source ‣ différents types : - constantes représentant une valeur entière - constantes représentant une valeur réelle - constante représentant un caractère - constante représentant une chaîne de caractères - ... ‣ Manière dont est écrite une constante : détermine son type. ‣ Si ambiguïtés : type par défaut ITC34 - Partie C / C++ 36 Benoît Darties Opérateurs Opérateurs Les opérateurs : ‣ définissent des opérations à effectuer sur des opérandes - opérateurs unaires : une opérande - opérateurs binaires : deux opérandes Types d’opérateurs : ‣ ‣ ‣ ‣ ‣ ‣ ‣ ‣ Opérateurs de calcul Opérateurs d’affectation Opérateurs d’incrémentation Opérateurs de comparaison Opérateurs logiques Opérateurs bit-à-bit Opérateurs de rotation de bits Liste des opérateurs : cf internet / cours shell (syntaxe proche) ITC34 - Partie C / C++ 37 Benoît Darties Manipulation: ‣ définis en conjonction avec le type des opérandes utilisés ‣ opérateurs binaires sur même types de données ‣ liste de tous les opérateurs : cf cours shell / internet Définitions multiples : ‣ exemple pour l’opérateur + - [int] + [int] : renvoie un int - [float] + [float] : renvoie un flottant ‣ Que se passe-t’il si l’on additionne un int avec un float ? ITC34 - Partie C / C++ Transtypage L’opérateur sizeof Opérateur sizeof Définition du transtypage ‣ faculté de convertir une variable d’un type donné en un autre type ‣ transtypage implicite : déduit logiquement du contexte - exemple : [int] + [float] - la valeur [int] est interprétée comme un flottants - opération réduite à [float] + [float] : retourne un flottant ‣ transtypage explicite : précisé par le programmeur - précision du type à convertir entre parenthèses avant la variable - lève les ambigüités et les restrictions de certains compilateurs - interpréter comme on le souhaite n’importe quelle zone mémoire - exemple : (float) [int] + (float) [int] - les valeurs [int] sont interprétées comme des flottants - opération réduite à [float] + [float] : retourne un flottant ITC34 - Partie C / C++ Benoît Darties 38 39 Benoît Darties ‣ Renvoie le nombre d’octets utilisée par : - une variable, qu’elle soit initialisée ou non - un type primitif ou composé ‣ Défini en tant que pseudo-opérateur, s’utilise comme une fonction ‣ Permet d’ajouter une couche d’abstraction int main() { int a; struct sockaddr_in b; char c; a a a a a = sizeof ( int ); = a + sizeof ( a ); += sizeof ( c ); -= sizeof ( b ); *= sizeof (struct sockaddr_in) ; ITC34 - Partie C / C++ Structures itératives non déterministes while (...) {...} : itérations pré-conditionnées while ( test ) { // instructions réalisées tant que le test est vrai ... } // // // // // affecte valeur 4 ajout valeur 4 ajout valeur 1 soustrait valeur 16 multiplie valeur 16 40 Benoît Darties Structures conditionnelles if (...) then { ...} else {...} if ( test ) { // suite d’instructions si le test est valide } else { // suite d’instruction si le test est invalide } do {...} while (...) : itérations post-conditionnées do { // instructions réalisées tant que le test est vrai // chaque instruction est réalisée au moins une fois ... } while ( test ); ITC34 - Partie C / C++ 41 Benoît Darties (...) ? ... : ... ; ( test ) ? instruction test OK : instruction si test !OK ; ITC34 - Partie C / C++ 42 Benoît Darties Structures conditionnelles Structures itératives switch ( ... ) { case ... case ... case ...} switch (variable à tester ) { case valeur1 : ... break; // instructions si variable = valeur1; // fin d’instructions! // Sinon poursuite des instructions case valeur2 : ... break; // instructions si variable = valeur2; default : ... // instructions dans tout autre cas // fin d’instructions! // Sinon poursuite des instructions Itérations déterministes : for ( ... ; ... ; ...) { ... } for ( affectation d’une variable; test ; incrémentation) { // instructions réalisées tant que le test est vrai ... } } ITC34 - Partie C / C++ 43 Benoît Darties ITC34 - Partie C / C++ Fonctions et procédures Fonctions et procédures Ensemble d’instructions groupées dans un bloc : ‣ Possèdent un identifiant ‣ Paramètres passés entre parenthèses, séparés par une virgule - données - résultats - données / résultats ‣ Valeur retour ? - une fonction retourne un résultat : ➡ nécessite un type ➡ valeur retournée du type défini ➡ possibilité de transtypage - une procédure n’en retourne pas. ➡ type void ITC34 - Partie C / C++ 45 Appel d’une fonction / procédure ‣ nom de la fonction / procédure suivi de la liste de ses paramètres ‣ exécution déroutée pour exécuter les instructions du bloc de fonction ‣ en fin d’exécution, retour au point de branchement, exécution des instructions suivantes ‣ Empilement de fonctions possibles Conditions nécessaires à l’appel d’une fonction ‣ le compilateur doit connaître l’utilisation de cette fonction - nom (identificateur) - paramètre(s) ? - valeur retour ? Benoît Darties ITC34 - Partie C / C++ Fonctions et procédures Etude d’un exemple : ‣ Signature : Permet d’identifier la fonction de manière unique ‣ Prototype : annonce la façon d’utiliser une fonction ‣ Déclaration : suite des instructions Lors d’un appel de fonction dans un programme : ‣ le prototype doit être connu - fichiers en-têtes .h - annonce du prototype avant l’appel ‣ si la fonction est déclarée avant l’appel : pas de problème ‣ appel sans déclaration préalable : - le compilateur suppose une déclaration post-appel - attribution d’un prototype par défaut (avec type int) - si prototype supposé différent de la déclaration : erreur ! 47 Benoît Darties 46 Fonctions et procédures Elements caractérisant les fonctions : ITC34 - Partie C / C++ Benoît Darties 44 Benoît Darties paramètres int addition(int v1, int v2) return v1 + v2 ; } int main() { int a; int b = 6; a = addition(5, b); { mot clé return Appel en précisant les valeurs de paramètres } Appel OK car fonction précédemment déclarée ITC34 - Partie C / C++ 48 Benoît Darties Fonctions et procédures Fonctions et procédures Etude d’un exemple : Etude d’un exemple : Lecture de haut en bas : Appel d’une fonction inconnue. Type supposé : int addition(int, int) int main() { int a; int b = 6; a = addition(5, b); } Avertissement : affectation d’un float avec un int int addition(int v1, int v2) return v1 + v2 ; } ITC34 - Partie C / C++ { La déclaration colle avec le prototype supposé : compilation et exécution OK Benoît Darties 49 float addition(float v1, float v2) return v1 + v2 ; } { La déclaration ne colle pas avec le prototype supposé int addition(float, float) introuvable ITC34 - Partie C / C++ Fonctions et procédures Benoît Darties 50 Fonctions et procédures Etude d’un exemple : Etude d’un exemple : float addition(float , float ); int main() { float a; float b = 6.0; a = addition(5.0, b); } prototype annoncé prototype annoncé float addition(float , float ); Lecture de haut en bas : Appel d’une fonction float addition(float, float) float addition(float v1, float v2) return v1 + v2 ; } ITC34 - Partie C / C++ Lecture de haut en bas : Appel d’une fonction inconnue. Type supposé : int addition(float, float) int main() { float a; float b = 6.0; a = addition(5.0, b); } { déclaration de la fonction float addition(float, float) introuvable. Erreur à la compilation déclaration de la fonction float addition(float, float) Benoît Darties 51 Lecture de haut en bas : Appel d’une fonction float addition(float, float) int main() { float a; float b = 6.0; a = addition(5.0, b); } ITC34 - Partie C / C++ 52 Benoît Darties Fonctions et procédures Etude d’un exemple : float addition(float , float ); int main() { float a; float b = 6.0; a = addition(5.0, b); } prototype annoncé Lecture de haut en bas : Appel d’une fonction float addition(float, float) int addition(float v1, float v2) { return v1 + v2 ; Ne colle } pas avec le prototype. Identificateur de fonctions déja réservé . Conflit de signature !!! ITC34 - Partie C / C++ 53 Benoît Darties Compilation d’un programme 54 Compilation de code Compilation de code Compilateurs de référence : Objectif de la compilation : ‣ Traduire un code source (fichier ASCII écrit par un utilisateur) en un code cible (fichier binaire) directement interprétable par le processeur ‣ Nécessité d’un compilateur Le compilateur : ‣ programme informatique ‣ traduit le code source en code cible ‣ généralement : - code source écrit en langage de programmation - code cible résultant en langage assembleur ou en langage machine ITC34 - Partie C / C++ Benoît Darties 55 ‣ pour le langage C : gcc ‣ pour le langage C++ : g++ ‣ pour le langage JAVA : javac Ex : compiler un programme C avec gcc ‣ gcc fichierSource.c -o fichierCible ‣ production du code fichierCible à partir du code fichierSource.c ‣ Simple et efficace ... jusqu’à un certain point ... gcc code source .c ITC34 - Partie C / C++ Compilation de code ‣ lecture du code source ‣ interprétation des directives de précompilation - définies dans le code source par une ligne commençant par # - #include, #define, #ifndef, #endif ... ‣ remplacement par la valeur associée dans le code source ‣ production de code source enrichi ‣ visualiser le code source enrichi sur stdout avec gcc : option -E compilateur code source enrichi code source ITC34 - Partie C / C++ Benoît Darties Fonctionnement du préprocesseur Préprocesseur Compilateur Assembleur Edition de lien préprocesseur 56 Rôle du préprocesseur Etapes de la compilation d’un fichier sous gcc : ‣ ‣ ‣ ‣ code exécutable assembleur code assembleur 57 Exemple : directives #include <...> et #include "..." Edition de liens code objet code exécutable Benoît Darties ‣ ligne remplacée par le contenu du fichier header correspondant - #include <fichier.h> : recherche fichier.h dans le répertoire usuel - #include "fichier.h" : recherche fichier.h dans le répertoire courant ITC34 - Partie C / C++ Rôle du compilateur 58 Benoît Darties Rôle du compilateur 1. analyse lexicale ‣ élimination du bruit : - commentaires /* .. */ ou // - espaces redondants ‣ découpage du texte en petits mots ‣ reconnaissance des mots-clés et des opérateurs ‣ identification des variables - utilisation d’une table des symboles - correspondance identifiant / nom de variable ‣ génération de jetons (token) - unités lexicales ou lexèmes - mots clés, identifiants ... Fonctionnement du compilateur ‣ ‣ ‣ ‣ ‣ lecture du code source enrichi analyse du code (vision logique) : 1. analyse lexicale 2. analyse syntaxique 3. analyse sémantique génération de code intermédiaire optimisation du code génération du code objet ITC34 - Partie C / C++ 59 Benoît Darties ITC34 - Partie C / C++ 60 Benoît Darties Rôle du compilateur Rôle du compilateur 1. analyse lexicale int main ( int = b = if a 5 = a ( 1. analyse lexicale { a int c ) 8 + c = ; , c ( > 2099 0 ; 245 c = a + ( 245 * b ) ; c = a + ( 245 * b ) ; id(3) aff id(1) add ob mul id(2) cb eol Table des symboles pos * ) b ) ; { nom 1 a ... 2 b ... 3 c ... ; nbr(245) } } ITC34 - Partie C / C++ 61 Benoît Darties ITC34 - Partie C / C++ Rôle du compilateur Benoît Darties 62 Rôle du compilateur 2. analyse syntaxique c = a + ( id(3) aff id(1) add ob 245 * b ) ; mul id(2) cb eol Table des symboles 2. analyse syntaxique ‣ rôle : identifier la structure syntaxique du programme ‣ Conversion de la suite de lexème en arbre syntaxique ‣ Représentation des relations entre les lexèmes pos nom 1 a ... 2 b ... 3 c ... nbr(245) aff id(3) add id(1) mul nbr(245) ITC34 - Partie C / C++ 63 Benoît Darties ITC34 - Partie C / C++ Rôle du compilateur id(2) Benoît Darties 64 Rôle du compilateur Génération de code intermédiaire ‣ code interne au compilateur ‣ encore très proche du code utilisateur 3. analyse sémantique ‣ Ajout des informations sémantiques sur l’arbre syntaxique ‣ Vérification de type ‣ Vérification de la conformité des opérateurs - pas de comparaisons entre types incomparables - pas d’affectation non autorisées - ... ‣ Vérification de la validité de l’appel à une fonction (prototype présent) Optimisation du code ‣ rendre le programme plus rapide ‣ garder des délais de compilation raisonnables Code non optimisé Code optimisé tmp1 te<- EntVersRéel(60) tmp2 <- mulRéel(id(3), tmp1) tmp3 <- addRéel(id(2), tmp2) id(1) <- tmp3 tmp1 <- mulRéel(id(3), 60.0) id(1) <- addRéel(id(2), tmp1) Création du code assembleur ITC34 - Partie C / C++ 65 Benoît Darties ITC34 - Partie C / C++ 66 Benoît Darties Rôle du compilateur Rôle de l’assembleur Exemple de code assembleur Traduction code assembleur en code machine .text .globl _main _main: LFB2: ! pushq! %rbp LCFI0: ! movq! %rsp, %rbp LCFI1: ! movl! $50, -4(%rbp) ! cmpl! $40, -4(%rbp) ! jne!L2 ! movl! $30, -8(%rbp) ! jmp!L6 L2: ! movl! $500, -8(%rbp) L6: ! leave ! ret int main() { int a=50; int b; if (a==40) { b = 30; } else { b = 500; } } ITC34 - Partie C / C++ 67 Benoît Darties .text .globl _main _main: LFB2: ! pushq! %rbp LCFI0: ! movq! %rsp, %rbp LCFI1: ! movl! $50, -4(%rbp) ! cmpl! $40, -4(%rbp) ! jne!L2 ! movl! $30, -8(%rbp) ! jmp!L6 L2: ! movl! $500, -8(%rbp) L6: ! leave ! ret ITC34 - Partie C / C++ L’édition de liens Programme et fonctions externes : Deux types de librairies : ‣ Un programme utilise des éléments déjà existants : - fonctions standard : main(), printf() ... - appels systèmes - ... ‣ Eléments «annoncés» dans le code source : - déclaration de prototypes de fonctions - utilisation de fichiers headers (.h), par exemple stdio.h ‣ La déclaration des fonctions utilisées n’est pas dans le code machine qui a été compilé jusqu’à présent ‣ librairies statiques ‣ librairies dynamiques Librairies statiques ‣ Extension .a sous UNIX ‣ Associées à l’exécutable généré ‣ Avantage : - Tout est inclus : pas de problème de dépendance - distribution de l’application facilitée ‣ Inconvénients : - exécutable relativement lourd - si modification : recompilation de la librairie ET de l’exécutable Intérêt de l’édition de lien : ‣ Lien entre le code machine et le code des fonctions externes ‣ Réutilisation des fonctions précédemment développées 69 Benoît Darties 68 L’édition de liens ITC34 - Partie C / C++ 0000000 cf fa ed fe 07 00 00 01 03 00 00 00 01 00 00 00 0000010 03 00 00 00 50 01 00 00 00 20 00 00 00 00 00 00 0000020 19 00 00 00 e8 00 00 00 00 00 00 00 00 00 00 00 0000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000040 70 00 00 00 00 00 00 00 70 01 00 00 00 00 00 00 0000050 70 00 00 00 00 00 00 00 07 00 00 00 07 00 00 00 0000060 02 00 00 00 00 00 00 00 5f 5f 74 65 78 74 00 00 0000070 00 00 00 00 00 00 00 00 5f 5f 54 45 58 54 00 00 Benoît Darties ITC34 - Partie C / C++ L’édition de liens Benoît Darties 70 Récapitulatif : compilation via gcc gcc et options Librairie dynamique ‣ Extension .so sous UNIX, .dylib sous MacOS X ‣ Associées au processus durant son exécution, quand nécessaire ‣ Avantage : - Exécutable distribué plus léger - Chargée une seule fois en mémoire, meme si utilisée par plusieurs exécutables - Si modification de la librairie (hors prototype), l’exécutable n’a pas besoin d’être recompilé ‣ Inconvénients : - problème de dépendances - librairies non conformes sur autres systèmes - versions de librairies - temps de lancement plus long ITC34 - Partie C / C++ 71 Benoît Darties préprocesseur code source .c compilateur code source enrichi assembleur code assembleur Edition de liens code objet code exécutable gcc -E gcc -S gcc -c gcc ITC34 - Partie C / C++ 72 Benoît Darties Récapitulatif : compilation via gcc Compilation sur plusieurs fichiers ‣ code source dispatché sur plusieurs fichiers ‣ compilation séparé de chaque fichier jusqu’au code objet ‣ mise en relation lors de l’édition de liens compilateur assembleur iti Ed préprocesseur on de code objet 1 préprocesseur compilateur code code source source .c enrichi ITC34 - Partie C / C++ Ed i ti on de lie ns code assembleur ns code source enrichi lie code source .c assembleur code assembleur code exécutable Types complexes : structures, tableaux code objet 2 73 Benoît Darties 74 Les structures Les structures Structure de données Structures de données ‣ Groupe (encapsulation) de variables : type complexe ‣ formé à partir : - de types simples - de types complexes précédemment définis // déclaration du type struct date { char jour; // char mois; // short int annee; // }; // Déclaration d’une structure ‣ mot clé struct ‣ liste des variables encapsulées entre accolades - type suivi d’un identificateur ‣ identificateur à la structure } Benoît Darties ITC34 - Partie C / C++ Les structures Benoît Darties Structures et opérateur sizeof // déclaration du type personne struct personne { char age; // entier de 0 à 150 struct date dateNaiss; // structure de type date }; int main () { struct personne Bobby; ‣ ‣ ‣ ‣ Retourne la somme des types composant la structure Besoin de connaître la taille des types avant de réserver la mémoire Taille connue au terme de la déclaration de la structure impossible de déclarer une structure dont la taille d’une des composantes n’est pas connue : // déclaration du type struct dateImbriquee { char jour; // char mois; // short int annee; // struct dateImbriquee }; Bobby.age = 29; Bobby.dateNaiss.jour = 17; Bobby.dateNaiss..mois = 7; Bobby.dateNaiss..annee = 1981; } 77 76 Les structures Structure de données imbriquées ITC34 - Partie C / C++ de 1 à 31 de 1 à 12 entre 0 et 9999 oublier le point-virgule uneDate.jour = 25; uneDate.mois = 12; uneDate.annee = 2010; ‣ ident_structure.ident_variable 75 entier entier entier ne pas // manipulation int main () { struct date uneDate; Accès aux éléments de la structure : ITC34 - Partie C / C++ date Benoît Darties ITC34 - Partie C / C++ dateImbriquee entier de 1 à 31 entier de 1 à 12 entier entre 0 et 9999 autreDate; // impossible !! 78 Benoît Darties Les structures Les tableaux Tableau : structure de données Structures et système ‣ ‣ ‣ ‣ de nombreuses structures sont pré-définies dans le système utilisées pour récupération de données systèmes déclaration présente dans les fichiers en-têtes (extensions .h) fonctions et appels systèmes : manipulent de nombreuses structures exemple : getpwent() ‣ récupération formatée des entrées de /etc/passwd ‣ manipule une structure struct passwd - déclaration dans le fichier en-tête pwd.h - voir manuel getpwent() ITC34 - Partie C / C++ 79 ‣ stocke plusieurs valeurs du même type ‣ type des valeurs à stocker annoncé dans la déclaration du tableau ‣ taille statique : - taille = nombre maximal d’éléments pouvant être stockés ➡ la taille doit être connue avant utilisation ➡ réservation de la mémoire nécessaire ‣ nombre d’éléments réellement stockés < taille ‣ en général : variable supplémentaire pour nombre d'éléments stockés Déclaration d’un tableau : ‣ type_element nom_tableau [ taille_tableau ] ; int tabEntiers[10] ; float tabFlottant[15] ; Benoît Darties ITC34 - Partie C / C++ Les tableaux 80 Benoît Darties Les tableaux Manipulation des éléments du tableau Tableaux multi-dimensionnels ‣ Cellules du tableau numérotées par des indices - indices numérotés de 0 à taille - 1 ‣ désignation de l’élément d’indice i : nom_tableau[ i ] ‣ Déclaration successives des dimensions // déclaration int matriceEntiers[10][20] ; float tabTriDimFlottant [45][50][60]; int tabEntiers[10] tabEntiers[0] tabEntiers[4] tabEntiers[9] int tabEntiers[10] ; // déclaration tableau de 10 entiers int a; tabEntiers[4] = 54; // cellule d’indice 4 affectée à 54 a = tabEntiers[4]; // lecture de la cellule d’indice 4 ITC34 - Partie C / C++ 81 Benoît Darties // manipulation matriceEntiers[9][5] = 6; tabTriDimFlottant[10][10][10] = matriceEntiers[9][5] * 4.0; matriceEntiers[10][5] = 6; // ERREUR ! // 10 est un indice hors limite // possible erreur de segmentation de la mémoire // ou écrasement d’une valeur // Que se passe-t’il en mémoire ? ITC34 - Partie C / C++ 82 Benoît Darties