Upload
polytechnice
View
1
Download
0
Embed Size (px)
Citation preview
Le langage C ISO 9899 (C90 et C99)
Jean-Paul Rigault Polytech’Nice Sophia
Université de Nice-Sophia Antipolis [email protected]
Contenu
1. Introduction 2. Premiers pas 3. Éléments du langage 4. Agrégats 5. Pointeurs 6. Préprocesseur 7. Fonctions 8. Structure des programmes 9. Bibliothèque standard, environnement…
http://www.polytech.unice.fr/~jpr/
7/02/10 ANSI C90-C99 2
Historique rapide (1)
Précurseurs Algol 60 (1960) et BCPL (1967) B : Ken Thomson, Bell Labs, 1970
Implémentation d’un nouvel OS (futur Unix)
Débuts du langage C Définition : Denis Ritchie, Bell Labs, 1972)
Premier compilateur en assembleur (Digital PDP 11) : Brian Kernighan, Denis Ritchie, Bell Labs
Réécriture d’Unix (en un été !)
Compilateur portable (pcc) : Steve Johnson, Bell Labs, 1975
7/02/10 ANSI C90-C99 4
Historique rapide (2)
C « traditionnel » Défini dans le livre de B.W. Kernighan et D. Ritchie (1978)
Normalisation ANSI/ISO 1987 : début des travaux (comité ANSI X3-J11) 1989 : première norme (ANSI X3-159) 1990 : adoption par ISO (ISO 9899:1990, C90) 1999 : révision de la norme (ISO 9899:1999, C99)
À partir du début des années 1990, la normalisation se déroule en parallèle avec celle de C++
Ce cours utilise C99 7/02/10 ANSI C90-C99 5
Objectifs du langage C (1)
Langage de « haut niveau » facile à apprendre facile à implémenter (voire portable)
Langage d’implémentation de systèmes (logiciel de base) proche des instructions des processeurs simple et efficace manipulation d’adresses (pointeurs typés mais non vérifiés) pas de vérifications dynamiques typage permissif logiciel de grande taille ⇒ compilation séparée
7/02/10 ANSI C90-C99 6
Objectifs du langage C (2)
Portabilité des programmes portabilité au niveau du source éviter les mécanismes trop spécifiques d’une architecture bibliothèque standard (C standard library) pour fournir les
fonctionnalités manquantes dans le langage de base entrées-sorties chaînes de caractères allocation de mémoire dynamique gestion de processus, concurrence, parallélisme…
Environnement système et outils clairement définis
7/02/10 ANSI C90-C99 7
Évaluation du C traditionnel (1)
Avantages Efficace
registres, pointeurs, opérations sur octets, bits, etc. pas de vérification dynamiques…
Le programmeur est supposé responsable Bibliothèque standard étendue
E/S, chaînes de caractères, processus et concurrence… Milliards de lignes écrites en C
Bibliothèques diverses : graphiques, scientifiques, commerciales… Logiciels de base : compilateurs, systèmes d’exploitation, bases de
données… 7/02/10 ANSI C90-C99 8
Évaluation du C traditionnel (2)
Avantages (suite)
Interface propre avec Unix et Unix-like recré une sorte d’environnement à la Unix sous d’autres systèmes favorise la portabilité entre systèmes
Bon assembleur portable Utilisé comme langage cible par certains compilateurs
(C++, Objective C, Eiffel, Modula 3...)
Vraiment portable ! Unix comme preuve : presque totalement écrit en C
Linux (DEC Alpha, Intel PC, Sun Sparc, Motorola PowerPC & 68000…)
Projet gnu (Free Software Foundation) Compilateurs, éditeurs, environnements de programmation…
7/02/10 9 ANSI C90-C99
Évaluation du C traditionnel (3)
Inconvénients Syntaxe à deux niveaux (préprocesseur) Le programmeur doit être responsable La compilation n’apporte que peu de vérifications
typage permissif (outils extérieurs comme lint) pointeurs délicats à utiliser
Vieux langage pas de généricité, de classes, d’objets… pas de gestion mémoire automatique approche vieillote de la modularité
7/02/10 10 ANSI C90-C99
Normalisation de C (1)
ISO C90 Évolution majeure du langage Amélioration de la portabilité
Bibliothèque standard clairement normalisé Identification claire des parties dépendantes de l’implémentation Internationalisation et localisation
Renforcement de la sécurité de programmation Vérifications de types plus stricte
Amélioration du préprocesseur
7/02/10 ANSI C90-C99 11
Normalisation de C (2)
ISO C99 Nettoyage et amélioration d’ISO C90 Extensions du langage
Booléens, entiers très longs, nombres complexes… Calculs en réel mieux maitrisés Tableaux de taille variable Optimisation (e.g., fonctions « en ligne ») Fonctions de manipulation de chaînes de caractères multi-octets
(e.g., unicode)
7/02/10 ANSI C90-C99 12
Compatibilité
Compatibilité ascendante excellente (mais pas totale) C traditionnel → C90 → C99 → C++
C traditionnel est actuellement (2008) obsolete Tous les compilateurs actuels supportent C90 (ANSI C) Un grand nombre supportent (une bonne partie de) C99
Cependant la compatibilité totale C99 est encore assez rare
7/02/10 ANSI C90-C99 13
Contexte du cours
Cours et exercices utilisent certaines extensions de C99 Environnement de développement de référence
Unix ou Unix-like (incluant Linux, MacOS X et Cygwin/Mingw) Compilateur gnu gcc 3.4.x ou 4.x (presque compatible C99) Éditeur emacs/xemacs ou autre avec décoration syntaxique et
compilation intégrée ou bien environnement de développement intégré comme kdevelop, eclipse, CodeLite, Code::Blocks…
Mise au point avec gdb (ou l’une de ses interfaces graphiques ou IDE)
Attention ! ms visual c++ n’est pas compatible C99 7/02/10 ANSI C90-C99 14
Un programme très simple
Compilation % gcc -o hello hello.c
Exécution % hello Hello, world! %
#include <stdio.h>
int main() { printf("Hello,world!\n"); return 0; }
7/02/10 ANSI C90-C99 2
Un programme multi-fichiers
Compilation % gcc -o hello f1.c f2.c
ou bien % gcc -c f1.c % gcc -c f2.c % gcc -o hello f1.o f2.o
Exécution % hello Hello, world! %
#include <stdio.h>
void say_hello(void) { printf("Hello,world!\n"); }
7/02/10z ANSI C90-C99
fichier f2.c
3
extern void say_hello(void);
int main() { say_hello(); }
fichier f1.c
Compilation séparée
7/02/10 ANSI C90-C99 4
f1.c f1.o
a.out
compilateur
gcc f1.c f2.c f3.c
pré- processeur
compilateur pré- processeur
compilateur pré- processeur
f2.c
f3.c
f2.o
f3.o
biliothèques utilisateur
biliothèque standard
éditeur de liens
Style de programmation en C Un langage d’expressions
#include <stdio.h>
int main() { int c; c = getchar(); while (c != EOF)
{ putchar(c); c = getchar(); } }
Style peu habituel en C
#include <stdio.h>
int main() { int c;
while ((c = getchar()) != EOF) putchar(c); }
C est un langage d’expressions
7/02/10 ANSI C90-C99 5
Style de programmation en C La boucle for
7/02/10 ANSI C90-C99 6
#include <stdio.h>
int main() { long n = 0; while (getchar() != EOF) n++; printf("%ld characters lus\n", n); }
#include <stdio.h>
int main() { long n; for (n = 0; getchar() != EOF; n++)
/* rien */; printf("%ld characters lus\n", n); }
Style de programmation en C Lecture et calcul
7/02/10 ANSI C90-C99 7
#include <stdio.h> #include <math.h>
int main() { double a, b, c, delta;
scanf("%lf %lf %lf", &a, &b, &c); delta = b*b - 4*a*c; if (delta < 0) printf("Pas de racines réelles\n"); else if (delta == 0.0) /* peu probable ! */ printf("Racine double : %.5f\n", -b/(2*a) ); else { double sqr_delta = sqrt(delta); printf("Deux racines : %g and %g\n", (-b - sqr_delta) / (2*a),
(-b + sqr_delta) / (2*a)); } }
Style de programmation en C Tableaux (1)
#include <stdio.h>
void insertion_sort(int n, int t[]) { // voir poly... }
#define NMAX 100
int main() { int n; int t[NMAX]; for (n = 0; n < NMAX && scanf("%d" , &t[n]) != EOF; ++n) {} insertion_sort(n, t); for (int i = 0; i < n; ++i) printf("%d " , t[n]); putchar(’\n’); }
7/02/10 ANSI C90-C99 8
Style de programmation en C Tableaux (2)
Remarque : tableaux à dimension variable de C99 Le prototype
void insertion_sort(int n, int t[]); peut s’écrire en C99 void insertion_sort(int n, int t[n]);
Dans tous les cas il n’y a aucun test de débordement d’indice Il faut que n soit connu avant d’être utilisé comme dimension
void insertion_sort(int t[n], int n) serait incorrect
7/02/10 ANSI C90-C99 9
Style de programmation en C Arguments de main
#include <stdio.h>
unsigned fibo(unsigned n) { return n < 2 ? 1 : fibo(n – 1) + fibo(n – 2); }
int main(int argc, char *argv[]) { unsigned i = atoi(argv[1]); printf("fibo(%d) = %d\n", fibo(n)); return 0; }
7/02/10 ANSI C90-C99 10
7/02/10 ANSI C90-C99 2
Éléments lexicaux Jeu de caractères
Identificateurs Sur-ensemble de ISO 646-1983 Invariant Code Set En fait, code ASCII Pas d’accents ou de caractères étrangers dans les identificateurs
Chaînes de caractères Jeu de caractères quelconque mono-octet
ASCII, ISO Latin1 ou 15 (ISO 8855-1 ou -15) Fonctions standard de manipulations de chaînes
éventuellement multi-octets Unicode, UTF-8… Seulement manipulable de manière sure sous C99
7/02/10 ANSI C90-C99 2
7/02/10 ANSI C90-C99 3
Éléments lexicaux Structure lexicale du source
Commentaires commentaires ligne (C99) : // jusqu'à fin de ligne commentaires (éventuellement multi-lignes) : /* bla bla */
Éléments lexicaux mots-clés : if for while identificateurs : main foo _MAX constantes arithmétiques : 12 23L 14.5 1.5E+06 ’a’ chaînes de caractères littérales : "hello\n" opérateurs : + ++ ^ * séparateurs : ; : { } ( [
7/02/10 ANSI C90-C99 3
7/02/10 ANSI C90-C99 4
Éléments lexicaux Identificateurs
Noms de constantes, variables, fonctions, macros… Syntaxe
suite de lettres et chiffres débutant par une lettre le caractère _ est considéré comme une lettre sensibilité à la casse (majuscules et minuscules différentes)
ident Ident IDENT foo x1 x2 _1997 SquareRoot square_root __DATE__
7/02/10 ANSI C90-C99 4
7/02/10 ANSI C90-C99 5
Éléments lexicaux Mots réservés (mots-clés)
C90 : 32 mots-clés auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while
C99 ajoute restrict inline _Complex _Imaginary _Bool
7/02/10 ANSI C90-C99 5
7/02/10 ANSI C90-C99 6
Types de C Panorama
Types de base Types utilisateur
Type vide • void Types scalaires de nature entière Integral types
• booléen (_Bool, bool) • char signé (signed) ou
non (unsigned) • int (short, long, long long) signé (défaut) ou non (unsigned)
• pointeurs • énumérations (enum)
Types scalaires de nature réelle Real types
• float • double • long double
Agrégats • tableaux • structures (struct) • unions (union)
7/02/10 ANSI C90-C99 6
7/02/10 ANSI C90-C99 7
Types de base de C Booléen
C90 pas de booléen on utilise la valeur de vérité (VV) des entiers
VV(e) est faux si e = 0, vrai sinon (-3 et 5 sont vrais !)
C99 Type _Bool avec les valeurs 0 et 1 (!) Après inclusion de <stdbool.h>
type bool avec valeurs true et false
Compatible avec valeur de vérité de C90
7/02/10 ANSI C90-C99 7
7/02/10 ANSI C90-C99 8
Types de base de C Caractères
Character (char) Représentation sur un octet
’a’ ’\012’ (code octal) ’\xff’ (code hexadécimal)
Séquences d'échappement ’\’’ la ‘ elle-même ’\\’ le \ lui-même ’\n’ fin de ligne newline ’\t’ tabulation horizontale horizontal tab ’\v’ tabulation verticale vertical tab ’\b’ retour arrière backspace ’\r’ retour chariot (carriage) return ’\f’ saut de page form feed ’\a’ cloche audible bell
7/02/10 ANSI C90-C99 8
7/02/10 ANSI C90-C99 9
Types de base de C Chaînes de caractères
Chaînes de caractères (char *) "hello, world\n" "avec une \" double quote"
Représentation en mémoire d'une chaîne de caractères
Le caractère nul final marque la fin de la chaîne mais n'en fait pas partie
Les fonctions de manipulation de la bibliothèque standard reposent sur cette hypothèse d'un nul final
Ne pas confondre 'a' et "a"
7/02/10 ANSI C90-C99 9
h e l l o , w o r l d \n \0
7/02/10 ANSI C90-C99 10
Types de base de C Constantes littérales entières et réelles
Constantes littérales entières int : 12 -24 long int : 12l -24L unsigned int : 12u 3U 0123 0xFa37 0Xffbb long long int : 12LL
Constantes littérales réelles float : 12.35f -24.2F 1.5E-3f double : 12.35 -24.2 6.02E+23 long double : 12.35L 1.E-648L
7/02/10 ANSI C90-C99 10
7/02/10 ANSI C90-C99 11
Types de base de C Déclarations de variables simples
/* simple déclarations */ int x; int a, b, c;
/* déclaration et initialisation */ unsigned int v1 = 0xabcd; unsigned long int v2, v3 = 1234UL; // v2 non initialisé float v4 = 123.45,
v5 = 0.0;
/* déclarations de constantes */ const int SIZE = 100; const double PI = 3.14159;
7/02/10 ANSI C90-C99 11
7/02/10 ANSI C90-C99 12
Types utilisateur de C Énumérations (1)
Définitions du type et des objets du type Définition du type seulement
enum light {GREEN, ORANGE, RED};
Définition d'objets du type (après la définition pécédente) enum lights l1, l2 = GREEN;;
Définition du type et d'objets du type enum light {GREEN, ORANGE, RED} l1, l2 = GREEN;
Type anonyme enum {GREEN, ORANGE, RED} l1, l2 = GREEN; il n'est plus possible de définir de nouveaux objets de ce type
7/02/10 ANSI C90-C99 12
7/02/10 ANSI C90-C99 13
Types utilisateur de C Énumérations (2)
Les valeurs des enum sont des constantes entières enum lights { GREEN, // = 0 ORANGE, // = 1 RED // = 2 };
On peut spécifier (certaines) valeurs enum lights {
GREEN = 12, ORANGE, // = 13 RED = 3 };
7/02/10 ANSI C90-C99 13
7/02/10 ANSI C90-C99 14
Types de C Synonymie de types : typedef
typedef unsigned int u_int; Simple synonymie : u_int et unsigned int sont
interchangeables u_int ui = 37U; unsigned int uj = ui;
typedef enum light {GREEN, ORANGE, RED} light; light l1, l2 = GREEN;
7/02/10 ANSI C90-C99 14
7/02/10 ANSI C90-C99 15
Instructions et expressions
Une expression retourne une valeur 3 + 4*x x = 3 // affectation, valeur : 3
En C, une instruction élémentaire est simplement une expression terminée par un ;
3 + 4*x; // cette instruction ne fait rien x = 3; // affecte 3 à x
7/02/10 ANSI C90-C99 15
7/02/10 ANSI C90-C99 16
Expressions Opérateurs : priorité et associativité
Opérateurs Assoc Opérateurs Assoc
1 postfixe () [] -> . ++ -- GD 8 et bit à bit & GD
2 unaire ! ~ + - * & ++ -- (cast) sizeof
DG 9 ou exclusif bit à bit ^ GD
3 multiplicatif * : % GD 10 ou bit à bit | GD
4 additif + - GD 11 et séquentiel && GD
5 décalage << >> GD 12 ou séquentiel || GD
6 relationnel < <= > >= GD 13 conditionnelle ?: DG
7 égalité == != GD 14 affectation = += /= etc.
DG
15 virgule , GD
7/02/10 ANSI C90-C99 16
7/02/10 ANSI C90-C99 17
Expressions Affectations (1)
Affectation simple: x = 3 i = x – 2
Affectations composées : += -= *= /= <<= etc. x += 3 i -= x – 1
a ϖ= b ≡ a = aϖ(b) avec une seule évaluation de a ϖ peut être : + - * / % << >> & ^ |
Incrémentation et décrémentation : ++ -- x = 3; i = ++x // préfixe : i vaut 4 et x aussi i = x++ // postfixe : i vaut 3 et x vaut 4 t[i++] = v[i++]; // ordre évaluation non garanti
7/02/10 ANSI C90-C99 17
7/02/10 ANSI C90-C99 18
Expressions Affectations (2)
L'opérande de gauche doit être une référence i.e., le nom d'un objet (non constant) C désigne une telle référence par l-value
Conversions lors d'une affectation La valeur de l'opérande droit est convertie dans le type de
l'opérande gauche Valeur et type d'une expression d'affectation
La nouvelle valeur de l'opérande gauche dans le type de cet opérande
Affectation multiple a = b = c = 2 *d + 3
7/02/10 ANSI C90-C99 19
Expressions Opérations sur les types (1)
Taille d'un type (sizeof) Par définition sizeof(char) == 1 Évaluation statique (à la compilation) Exemples
sizeof(x) sizeof(enum light)
int a[10]; const int n = sizeof(a) / sizeof(a[0]); /* nombre d'éléments dans le tableau */ const int n = sizeof(a) / sizeof(int); /* idem */
7/02/10 ANSI C90-C99 19
7/02/10 ANSI C90-C99 20
Expressions Opérations sur les types (2)
Coercion de type (cast) (type) expression l'expression est évaluée (dans son type) puis le résultat est
converti si possible dans le type indiqué résolu à la compilation aucune vérification dynamique
int i = (int)2.0; double x = 3 / (float)4; // = 0.75 x = 3 / 4; // = 0 division entière
7/02/10 ANSI C90-C99 20
7/02/10 ANSI C90-C99 21
Expressions Opérateurs sur la représentation binaire
Décalages : a<<b a>>b Décale a de b positions de bit dans le sens indiqué Portable si b > 0 et a non signé (unsigned)
Opérateurs de conjonctions et disjonction bit à bit et bit à bit : a&b ou exclusif bit à bit : a^b ou bit à bit : a|b
7/02/10 ANSI C90-C99 21
7/02/10 ANSI C90-C99 22
Expressions Opérateurs relationnels
Égalité : a==b a!=b Comparaisons : a<b a>b a<=b a>=b
Attention à = et == if (a = 0) … // toujours faux !
Conjonctions et disjonction : a&&b a||b Évaluation séquentielle
a&&b ≡ a ? b : false a||b ≡ a ? true : b
Tous ces opérateurs sont associatifs (de gauche à droite) a < b < c : compare a < b (0 ou 1) à c
7/02/10 ANSI C90-C99 22
7/02/10 ANSI C90-C99 23
Expressions Opérateur conditionnel
a ? b : c Retourne b si a est vrai, sinon retourne c Une seule des deux expressions b ou c est évaluée
int min (int a, int b) { return a < b ? a : b; }
int abs(x) { return x < 0 ? -x : x; }
7/02/10 ANSI C90-C99 23
7/02/10 ANSI C90-C99 24
Expressions Opérateurs d'évaluation séquentielle
Opérateur virgule x = (e1, e2, e3);
Évalue successivement e1, puis e2, puis e3 et retourne la valeur de cette dernière expression (qui est ensuite effectée à x)
La faible priorité de cet opérateur impose les parenthèses
Pour mémoire : a&&b a||b if (i < n && t[i] == 0) …
7/02/10 ANSI C90-C99 24
7/02/10 ANSI C90-C99 25
Expressions Type d'une expression
Une expression a son propre type qui est évalué par le compilateur
Ce type ne dépend que du type des opérandes de l'expression L'évaluation se fait
récursivement, par sous-expression
Le context ne joue aucun tôle dans l'évaluation du type
7/02/10 ANSI C90-C99 25
x = (a + b) * 2 + c
T(a+ b) * 2
Ta + b
T(a+ b) * 2 + c
Ta Tb int Tc Tx
convertible
7/02/10 ANSI C90-C99 26
Expressions Conversions implicites (1)
C permet le mélange de types dans les expressions Le compilateur applique alors des conversions implicites
1. Promotions entières : char et short → int Il n'y a pas en C d'expression de type short ou char
2. Hiérarchie de types (simplifiée) 1. long double 2. double 3. float 4. unsigned long 5. unsigned int 6. int
7/02/10 ANSI C90-C99 26
7/02/10 ANSI C90-C99 27
Expressions Conversions implicites (2)
Conversion lors d'une affectation, d'une initialisation, d'un passage de paramètres et d'un retour de fonction L'expression de droite est convertie dans le type de l'opérande
gauche int i = 2.7; // i == 2 (troncature vers 0) int j = -2.7; // i == -2 (troncature vers 0)
Ceci peut provoauer des effets bizarres char c; c = 2784; // valeur de c non portable
Conversions préservant la valeur (mais pas nécessairement la précision) : toujours légales
Conversions ne préservant pas la valeur : warning
7/02/10 ANSI C90-C99 27
7/02/10 ANSI C90-C99 28
Instructions Panorama (1)
Instruction simple Instruction élémentaire
Expression terminée par un point-virgule 0; x = 3;
Instructions de contrôle Sélections : if switch Boucles : while for do...while Ruptures de séquence : goto(!) break continue return
7/02/10 ANSI C90-C99 28
7/02/10 ANSI C90-C99 29
Instructions Panorama (2)
Bloc Suite d'instructions et déclarations entre accolades Les blocs peuvent être imbriqués Utilisation
Groupement d'instructions while (a < b) { a += 2; b--;} Localité des variables while (a < b) { int i = 2*a; ...} Corps d'une fonction int f(int n) {...}
Instructions Bloc
Variables locales d'un bloc Elles n'ont d'existence que
dans le bloc Elles sont allouées à chaque
entrée dans le bloc et désallouées à chaque sortie
En C90, les définitions des variables locales doivent être en début de bloc, avant les autres instructions
Ceci n'est pas nécessaire en C99
int f(int i) { int j = 2*i; int k; j += 2 –k; double x = j; // C99 x *= 2; return x; }
7/02/10 ANSI C90-C99 30
7/02/10 ANSI C90-C99 31
Instructions Instruction vide
while ((c = getchar()) != SPACE) /* rien */;
while ((c = getchar()) != SPACE); Le point-virgule est un terminateur d'instruction (simple)
while ((c = getchar()) != SPACE) {} Un bloc n'a pas besoin d'être (ne doit pas être) terminé par un
point-virgule
7/02/10 ANSI C90-C99 31
7/02/10 ANSI C90-C99 32
Instructions Affectation
Affectation simple x = e;
Effet de bord : la valeur de l'opérande gauche change
Expression et instruction d'affectation Un expression a un type et une valeur Une instruction n'a rien de tel
while ((c = getchar()) != EOF) ... c = getchar();
Affectation composée (pour mémoire) x += e; (-= *= /= %= etc.)
7/02/10 ANSI C90-C99 32
7/02/10 ANSI C90-C99 33
Instructions Sélection : if (1)
if (expression) instruction1; else instruction2;
La partie else est optionnelle instruction1 et 2 sont soit une instruction simple soit un
bloc L'expression (en générale entière) est évaluée pour sa
valeur de vérité : 0 est faux 1 est vrai
7/02/10 ANSI C90-C99 33
7/02/10 ANSI C90-C99 34
Instructions Sélection : if (2)
if (x) { /* équivalent à (x != 0) */ printf("%d est vrai\n", x); a += b*c; } else printf("%d est faux\n", x);
if (x < y) { if (x > z)
printf("x est compris entre z et y\n"); else printf("x est < à y et <= z\n");
} 7/02/10 ANSI C90-C99 34
7/02/10 ANSI C90-C99 35
Instructions Sélection : switch (1)
switch (expression) { case val1: list-instr1 case val2: list-instr2 ... case valn: list-instrn default: list-instr_def }
Les vali sont des constantes entières de compilation
La clause default et sa list-instr sont optionnelles
L'expression est évaluée et comparé successivement aux vali L'égalité fournit le point d'entrée Puis on exécute toutes les list-
instrj=i, i+1, ...,n ainsi que list-instr_def
break permet de sortir prématurément du switch
7/02/10 ANSI C90-C99 35
7/02/10 ANSI C90-C99 36
Instructions Sélection : switch (2)
char c; ... switch (c) { case '_' : printf("Pour C, '_' est une "); case 'a' : case 'A' : ... case 'z' : case 'Z' : printf("lettre\n"); break; case ' ' : case '\t': print("espace\n"); break; default : printf("autre caractère\n"); }
7/02/10 ANSI C90-C99 36
7/02/10 ANSI C90-C99 37
Instructions Boucle : while et do...while (2)
while (expression) instruction
do instruction while (expression);
Les expressions sont évaluées pour leur valeur de vérité Pour while le test a lieu en début de boucle et pour do...while en fin le corps d'une boucle while peut donc ne pas être exécuté celui d'un do...while l'est toujours au moins une fois
7/02/10 ANSI C90-C99 37
7/02/10 ANSI C90-C99 38
Instructions Boucle : for (1)
for (initialisation; expression; entretien) instruction;
équivalent à initialisation; while (expression) { instruction; entretien; }
Tout le contrôle de boucle est localisé en une seule clause
7/02/10 ANSI C90-C99 38
7/02/10 ANSI C90-C99 39
Instructions Boucle : for (2)
Style traditionnel
i = 0; while (i < 100) { t[i] = 0; i = i + 1; }
Style C
for (i = 0; i < 100; i++) t[i] = 0;
7/02/10 ANSI C90-C99 40
Instructions Boucle : for (3)
Boucle à plusieurs indices for (i = 0, j = 0; i < N; ++i, j +=2) t[j] = u[i];
Modification de l'indice de boucle dans le corps for (i = 1; i < argc; ++i) { switch (argv[i][0]) { case '-' : switch (argv[i][0]) { case 'f' : filename = argv[++i]; break; ... } ... }
7/02/10 ANSI C90-C99 41
Instructions Boucle : for (4)
Indice de boucle local : C99 uniquement for (int i = 0; i < N; ++i) { // i est local à la boucle } // i n'est pas connu ici for (int i = 0; i < N; ++i) ... // pas de conflit
Si on veut que l'indice soit connu à l'extérieur : int i; for (i = 0; i < N; ++i) if (t[i] == 0) break; // ici i est connu...
7/02/10 ANSI C90-C99 42
Instructions Rupture de séquence : break
Permet de quitter le corps d'un switch ou d'une boucle pour passer en séquence Ne permet de quitter qu'un seul
niveau de switch/boucle
for (i =0; i < MAX; i++) if (t[i] == item) break;
for (i =0; i < MAX; i++) for (j =0; j < MAX; j++) if (t[i][j] == item) break; // incorrect ?
for (i =0; i < MAX; i++) { switch (t[i]) {
case 0 : ....; case 1 :
break; // incorrect ? ... } }
7/02/10 ANSI C90-C99 42
7/02/10 ANSI C90-C99 43
Instructions Rupture de séquence : continue
Permet de quitter prématurément le corps d'une boucle pour exécuter l'itération suivante Ne permet de continuer qu'un
seul niveau de boucle Pour une boucle for, les
instructions d'entretien de la boucle sont exécutées lros du passage à l'itération suivante, ainsi que le test de la condition
for (i =0; i < MAX; i++) { if (t[i] < 0) continue; ... }
for (i =0; i < MAX; i++) { switch (t[i]) { case 0 : ....;
case 1 : continue; // OK ... } ... }
7/02/10 ANSI C90-C99 43
7/02/10 ANSI C90-C99 44
Instructions Rupture de séquence : return
return; return expression;
Quitte la fonction courante Spécifie la valeur retournée
par cette fonction Les fonctions à type de retour
void n'on pas de valeur de retour
L'expression est convertie dans le type de retour de ka fonction, si nécessaire (et possible)
int min(int a, int b) { if (a < b) return a; else return b; }
int min(int a, int b) { return (a < b) ? a : b; }
int search(int v, int t[], int sz) { for (int i = 0; i < sz; i++) { if (t[i] == item) return i; } return -1; }
7/02/10 ANSI C90-C99 44
7/02/10 ANSI C90-C99 45
Instructions Rupture de séquence : goto
Sortie de plusieurs boucles à la fois for (int i = 0; i < M; ++i) for (int j = 0; j < N; ++j) if (t[i][j] == val) goto found; found: // suite du code
De préférence, oubliez-le ! Il est toujours possible et assez facile de s'en passer Son abus (même léger) donne un code de style douteux,
difficilement lisible
Tableaux
Collection indexable d'objets homogènes (de même type) En C90, taille définie à la compilation L’index débute toujours à 0 Pas de test/exception de débordement d’indice Passés par référence (adresse) en paramètre de fonctions Non copiables/affectables directement Confusion tableaux-pointeurs voulues par les concepteurs de C
(voir chapitre Pointeurs)
Tableaux Tableaux mono-dimensionnels (1)
Déclaration int t[10]; double v[100]; #define N 20 unsigned short ust[2*N + 1];
Specification de la dimension Une expression constante évaluable à la compilation Les constantes const sont interdites en C90
Elles le sont aussi en C99, sauf éventuellement pour les tableaux automatiques const int N = 20; float ft[N]; // Interdit en C90 (et en C99 ?)
Tableaux Tableaux mono-dimensionnels (2)
Initialisation d’agrégat int t[4] = {1, 2, 3, 4}; int u[] = {1, 2, 3, 4}; // Le compilateur calcule la dimension double v[10] = {0.0, 1.1}; // Seuls 2 premiers éléments initialisés
Cette syntaxe n’est valide que pour une initialisation t = {1, 2, 3, 4}; // Interdit!
En C90, les valeurs d'initialisation doivent être des constantes de compilation Cette contrainte est levée en C99 pour initialiser des variables
automatiques (variables locales de bloc)
Tableaux Tableaux mono-dimensionnels (3)
Initialisation d’agrégat en C99 On peut désigner explicitement les composantes que l'on veut
initialiser L'ordre des initialisations n'a alors pas d'importance L'initialisation peut n'être que partielle
int t[] = { [1] = 3, [0] = 4, [3] = 5, },
Ici, la dimension de t (calculée par le compilateur) est 4 La composante d'indice 2 n'est pas initialisée
Tableaux Tableaux mono-dimensionnels (2)
Indexation Indices valides : 0, 1, ..., N-1 (N étant la dimension du tableau)
#define N 20 double v[N];
v[0] = 3.5; double x = v[2];
for (int i = 0; i < N; ++i) v[i] = 0.0;
Tableaux Tableaux mono-dimensionnels (2)
Autres opérations Copie
L’affectation de tableaux est interdite #define N 20 double v1[N], v2[N]; // ... v1 = v2; // Interdit
Il faut faire une boucle for (int i = 0; i < N; ++i) v1[i] = v2[i];
Autres opérations : E/S, éventuellement arithmétique... Là encore, faire des boucles
Tableaux Tableaux mono-dimensionnels (3)
L’opérateur sizeof Retourne la taille mémoire occupée par le tableau En C90, sizeof est toujours évalué à la compilation
En C99 aussi, sauf éventuellement pour les tableaux automatiques En C, on ne peut consulter à l’exécution la taille d’un tableau
Il faut donc la connaître par ailleurs...
Exemples #define N 20 double v1[N]; size_t n = sizeof(v1); // N * sizeof(double) size_t dim = sizeof(v1)/sizeof(double); // == N
Tableaux Chaînes de caractères
Ce n’est pas un type en soi ! Représentation comme un tableau de caractères (char) Toutes les propriétés des tableaux, plus
Chaînes littérales constantes : "hello" Terminaison conventionnelle par le caractère nul ('\0') Fonctions de la bibliothèque standard <string.h>
char s[] = "hello, world"; size_t n = strlen(s); // Longueur utile à l'exécution assert(s[strlen(s)] == '\0');
Tableaux Tableaux multi-dimensionnels
N'existent pas réellement en C Réalisés sous formes de « tableaux de tableaux » rangés
par ligne double mat[3][3]; double ident[][3] = { {1.0, 0.0, 0.0}, // ligne 0 {0.0, 1.0, 0.0}, // ligne 1 {0.0, 0.0, 1.0} // ligne 2 };
La syntaxe d'initialisation d'agrégat reflète cette notion de tableau de tableaux Noter que seule la première dimension peut être laissée à calculer par le compilateur
double ident[][] = ... ; // Interdit
Tableaux Tableaux à dimension variable de C99 (1)
En C90 la dimension d'un tableau est
une constante de compilation l'opérateur sizeof est évalué
à la compilation
En C99 la dimension d'un tableau
automatique, c'est-à-dire variable locale de bloc paramètre de fonction
peut être une variable l'opérateur sizeof est alors
évalué à l'exécution
// C99 uniquement int f(int n, int p[n]) { double t[2*n];
// Assertion suivante vraie
assert(sizeof(t) == 2*n*sizeof(double));
// Assertion suivante fausse ! assert(sizeof(p) == n*sizeof(int)); }
Il n'y a toujours pas moyen de consulter la taille d'un tableau passé en paramètre à l'exécution
Il n'y a toujours aucun test de débordement
Tableaux Tableaux à dimension variable de C99 (2)
En C99, il est maintenant possible de dimensionner un tableau automatique avec une constante (const) ... ... mais ceci reste interdit pour un tableau statique
const int N = 10; double st[N]; // Interdit : tableau statique void f() { int t[N]; // OK : tableau automatique // ... }
Structures
Regroupement d'un nombre fixé (à la compilation) d'objets de types possiblement différents Les objets contenus sont appelés champs
Copiable/affectable Copie bit à bit
Opération de sélection de champ Pas d'autre opérateurs définis
Structures Déclaration
Déclaration du type struct Person { // Person est le tag char name[20]; struct Date birthdate; };
Déclaration d'une variable du type struct Person lui; // struct Person est le type
Déclaration simultané du type et d'un objet struct Date { int day, month, year; } d1, d2; struct { int a; double x; } s1, s2; // type anonyme
Structures Initialisation
Initialisation d'agrégat struct Date { int day, month, year; };
struct Person { char name[20]; struct Date birthdate; };
struct Person jdoe = { "John Doe", // name { // birthdate, un autre agrégat 29, // day 2, // month 1948 // year } };
Structures Initialisation des structures en C99
C99 étend la syntaxe d'initialisation d'agrégat en permettant de nommer
explicitement les champs à initialiser L'ordre des initialisations peut
donc être quelconque L'initialisation peut n'être que
partielle On peut aussi initialiser les
différents éléments d'un tableau
en autorisant des expressions non statiques lors de l'initialisation des variables automatiques
struct Person jane = { .birthdate.day = 12, .name = "Jane Doe", .birthdate.month = 2, };
struct Person couple[2] = { [0].name = "Jane Doe", [1].name = "John Doe",
};
struct Date d = {14, 7, 1789}; struct Person peter = { .name = "Peter Smith", .birthdate = d, };
Structures Copie
Les structures sont affectables struct Person jdoe = { ... }; struct Person jsmith;
jsmith = jdoe;
La copie s'effectue bit à bit Noter que les tableaux à l'intérieur d'une structure (e.g., name) sont
correctement copiés (alors qu'ils ne peuvent pas l'être directement) Les structures peuvent être passées en paramètre par valeur (mais il
vaut souvent mieux les passer par pointeur)
Il n'y a pas d'autre opérateur pour opérer globalement sur une structure (comme la comparaison == par exemple)
Structures Sélection de champ
Opérateur "point" struct Person jdoe = { ... }; size_t n = strlen(jdoe.name); if (jdoe.name[0]) == 'J') ... jdoe.birthdate.year = 1950;
struct Person crowd[1000]; int i; // ... crowd[i].birthdate.day++;
Le résultat d'une sélection est une référence (lvalue) On peut donc changer la valeur du champ par affectation
Structures Champs de bits (bitfields)
struct Instruction { unsigned int code_op : 8, unsigned int ri : 4, unsigned int rb : 4, unsigned int offset : 16, }; Les champs doivent être int ou l'une de ses variations En C99, il peuvent être aussi de type enum
Code op Reg index
Reg base Déplacement
8 bits 4 bits 4 bits 16 bits
Unions
Regroupement d'un nombre fixé (à la compilation) d'objets de types différents Mais les champs sont mutuellement exclusifs À un instant donné l'union ne contient donc qu'un seul objet Le type de l'objet courant n'est pas mémorisé dans l'union
C'est donc au programmeur de le gérer
Copiable/affectable Copie bit à bit
Opération de sélection de champ Pas d'autre opérateurs définis
Unions Déclaration
Déclaration du type union Mixed { // Mixed est le tag // un objet de ce type contient char c; // - soit un caractère int i; // - soit un entier double x; // - soit ou un réel };
Déclaration d'une variable du type union Mixed u; // union Mixed est le type
Déclaration simultané du type et d'un objet union { char c[4]; double x; } cr1, cr2; // type anonyme
Unions Initialisation
Utilisation de l'initialisation d'agrégat Une seule valeur doit être présente... et elle doit être du type du premier champ de l'union
union Mixed m1 = {'a'}; // OK union Mixed m2 = {3.5}; // Non // m2 contient le caractère dont le code est 3
En C99, possibilité de nommer les champs à initialiser union Mixed m1 = {.c = 'a'}; // toujours OK union Mixed m2 = {.x = 3.5}; // OK maintenant
Unions Copie
Les unions sont affectables union Mixed m1 = 'a'; union Mixed m2; m2 = m1;
La copie s'effectue bit à bit Aucun contrôle de type n'est effectué lors de la copie Les unions peuvent être passées en paramètre par valeur (mais il
vaut souvent mieux les passer par pointeur)
Il n'y a pas d'autre opérateur pour opérer globalement sur une structure (comme la comparaison == par exemple)
Union Sélection de champ
Opérateur "point" union Mixed m = { ... }; char c = m.c; double x = m.x; m.i = 12;
L'opérateur . indique la manière (le type) d'interpréter le contenu de l'union
Le résultat d'une sélection est une référence (lvalue) On peut donc changer la valeur du champ par affectation
Aucune vérification ni conversion n'est effectuée sur le contenu de l'union union Mixed m; m.i = 3; // un entier dans l'union double x = m.x; // relu comme un réel // surement incorrect
Unions Utilisation des unions
Permettre le partage de mémoire entre des objets exclusifs
Permettre des interprétations différentes de la même représentation mémoire
struct Instruction { ... }; union Machine_Word { int integer; struct Instruction instruction; };
Réaliser des structures à variantes...
Unions Utilisation des unions : structure à variantes
typedef struct Person { char name[30]; struct Date birthdate; enum {FEMALE, MALE} gender; union { char maiden_name[30]; bool national_service; } info; } Person;
Person bob = { "Bob Smith", {1,1,1940}, MALE }; // 4e champ ?? Person mary = { "Mary Smith", {1,1,1940}, FEMALE, "Mary Brown" }; bob.info.national_service = true; switch (mary.gender) { case MALE : printf("service national ? %d\n", mary.info.national_service); break; case FEMALE : printf("maiden name ? %s\n", mary.info.maiden_name); break; }
Unions Remarques sur l'utilisation des unions
Mécanisme intrinsèquement de bas niveau Aucun contrôle Aucune aide automatique au programmeur (e.g., conversion)
À utiliser avec précautions et à bon escient Utile en programmation système Ailleurs, la seule utilisation raisonnable est la définition de
variantes de structure à condition de prévoir un suivi correct du type de l'objet courant de
l'union
7/02/10 ANSI C90-C99 5-2
Motivation
Un pointeur est une variable (ou constante) dont la valeur est l'adresse d'un autre objet L'accès à ce dernier objet est donc indirect Les pointeurs de C sont typés
Les pointeurs sont fondamentaux en C La notion d'adresse est cruciale en programmation système L'utilisation de pointeurs rend le code
plus compact, plus efficace mais moins lisible et plus dangereux
Les pointeurs font partie du « génie » de C Maitriser C, c'est d'abord maitriser les pointeurs
7/02/10 2 ANSI C90-C99 7/02/10 5-2 ANSI C90-C99
7/02/10 ANSI C90-C99 5-3
Principe
int i = 4; int *pi = &i; printf("%d\n", *pi); // 4 *pi = 5;
pi est un (simple) pointeur il est initialisé à l'adresse de la variable
i l'opérateur & retourne l'adresse d'un
objet (donc une valeur de pointeur)
l'expression *pi retourne une référence sur l'objet pointé
donc *pi et i sont ici synonymes
pi
i *pi
7/02/10 5-3 ANSI C90-C99
4 5
7/02/10 ANSI C90-C99 5-4
Déclaration et initialisation
Déclaration simple int *p1, *p2; // 2 pointeurs sur entier int *p3, p4; // Un pointeur et un entier
Initialisation int i; double x; int *p1 = &i; double *px1, *px2 = &x; // px1 non initialisé
7/02/10 4 ANSI C90-C99 7/02/10 5-4 ANSI C90-C99
7/02/10 ANSI C90-C99 5-5
Opérateurs de base Opérateur &
L'opérateur & retourne l'adresse d'un objet il s'agit donc d'une valeur (constante) de type pointeur
L'opérateur & doit s'appliquer à une référence sur un objet l'objet référencé peut être une variable ou constante de
n'importe quel type et de n'importe quel mode d'allocation en mémoire ainsi qu'à une fonction
en revanche l'opérateur & ne peut s'appliquer à de pures valeurs int *p1 = &12; // pur non sens #define N 100 int *p2 = &n; // tout aussi stupide
7/02/10 5 ANSI C90-C99 7/02/10 5-5 ANSI C90-C99
7/02/10 ANSI C90-C99 5-6
Opérateurs de base Opérateurs d'indirection
Opérateur * *p retourne une référence sur
l'objet pointé par p
Opérateur -> Utile pour les pointeurs sur
structures et unions p->f équivalent à (*p).f
struct Coord {int x, y;}; struct Coord co = {0, 0}; struct Coord *pco = &co; pco->y = 2;
0
pco
co.x co.y pco->y 0 2
7/02/10 5-6 ANSI C90-C99
7/02/10 ANSI C90-C99 5-7
Pointeurs multiples
int i = 4; int *pi = &i; int **ppi = π int j; *ppi = &j; **ppi = 5;
ppi est pointeur sur un pointeur, un double pointeur sur entier
Donc *pi est (une référence sur) un simple pointeur sur entier
Et **ppi est (une référence sur) un entier
pi
i *pi
ppi
*ppi
**ppi
j
4
5
7/02/10 5-7 ANSI C90-C99
7/02/10 ANSI C90-C99 5-8
Cas particuliers de pointeurs
Pointeur nul Valeur NULL définie dans
<stdlib.h> De manière équivalente, valeur
(entière) 0 Le pointeur nul ne pointe sur rien Toute tentative d'indirection à
travers le pointeur nul est catastrophique int *pi = NULL; *pi = 12; // crashe !
Pointeur sur void (void *) C'est une adresse machine brute Tout pointeur est implicitement
convertible en void * et réciproquement int *pi; void *pv = pi; pi = pv;
Les opérations effectuables sur les void * sont restreintes comparaison, comparaison à 0 copie/affectation pas d'indirection, pas d'opération
arithmétique
7/02/10 5-8 ANSI C90-C99
7/02/10 ANSI C90-C99 5-9
Pointeurs et constantes
Pointeur constant int *const pc = &i; La valeur du pointeur ne change
pas: l'objet pointé est donc toujours le même (pc est constant)
Une tel pointeur doit être initialisé lors de sa définition
Pointeur sur une constante const int *p2c = &i; La valeur de l'objet pointé ne peut
changer (*p2c est constant)
*p2c = 13;// Interdit mais... i = 13; // toujours possible p2c = &i; // OK
Pointeur constant sur une constante const int *const pc2c; Combinaison des deux possibilités pc2c et *pc2c sont constants
Le compilateur vérifie la constance des pointeurs et interdit tout élargissement d'accès (cad toute conversion d'une constante en variable)
« Pointeur sur constante » ne signifie pas que l’objet pointé est réellement constant Il n’est simplement pas modifiable
par indirection du pointeur
7/02/10 9 ANSI C90-C99 7/02/10 5-9 ANSI C90-C99
7/02/10 ANSI C90-C99 5-10
Opérations sur pointeurs
Opérations de comparaison Égalité, inégalité : == != Mais aussi opérateurs relationnels : < <= > >=
Opérations arithmétiques et indexation (voir ci-après) Addition et soustraction d’un entier Différence de deux pointeurs Indéxation
Conversions Conversion implicite de et vers void * Toutes les autres conversions exigent un cast
7/02/10 5-10 ANSI C90-C99
7/02/10 ANSI C90-C99 5-11
Opérations sur pointeurs Addition et soustraction d’un entier
T *p; Soit n un entier positif ; T est un
type quelconque p+n pointe sur le nième objet de
type T suivant celui pointé par p p-n pointe sur le néme objet de
type T précédant celui pointé par p
On voit qu’il y a mise à l’échelle automatique des adresses machines
p
p-3
p+2 adresses croisantes
7/02/10 5-11 ANSI C90-C99
7/02/10 ANSI C90-C99 5-12
Opérations sur pointeurs Différence de deux pointeurs
T *p1, *p2; T est un type quelconque ; les
deux pointeurs doivent être de même type
p1 – p2 est le nombre algébrique d’objets de type T entre celui pointé par p1 et celui pointé par p2 ce nombre est positif si p1 > p2, négatif sinon
On voit qu’il y a mise à l’échelle automatique des adresses machines
La somme de deux pointeurs est autorisée mais n’a pas de sens
p1
p2 adresses croisantes
p2 – p1 == 5 p1 – p2 == -5
5
7/02/10 5-12 ANSI C90-C99
7/02/10 ANSI C90-C99 5-13
Opérations sur pointeurs Indexation de pointeur
T *p; Soit n un entier ; T est un type
quelconque p[n] est une référence sur le
nième objet de type T suivant si n > 0 (resp. précédant si n < 0) celui pointé par p
On a donc l’équivalence p[n] ≡ *(p+n)
p[2] *(p+2)
p[-3] *(p-3)
p
adresses croisantes
p-3
p+2
7/02/10 5-13 ANSI C90-C99
7/02/10 ANSI C90-C99 5-14
Opérations sur pointeurs Remarques sur opérations arithmétiques
Aucun test de validité n’est effectué ni à la compilation ni à l’exécution quant aux types des objets pointés Les opérations arithmétiques, mais aussi les opérateurs
relationnels peuvent donc donner des résultats sujets à caution
double t[10]; // Les allocations... int i; // en mémoire... char c; // sont surement... double u[5]; // consécutives double *p = &t[0]; *(p + 14) = 3.5; // compile correctement // mais est-ce raisonnable ?
7/02/10 5-14 ANSI C90-C99
7/02/10 ANSI C90-C99 5-15
Tableaux et pointeurs Confusion tableau/pointeur (1)
L’indexation des pointeurs conduit à considérer un nom de tableau comme un pointeur (sur son premier élément)
int t[6]; int *p = &t[0]; t[3] = 12; *(p+3) = 12; p[3] = 12; *(t+3) = 12;
t[3]
t[4]
t[5]
t[2]
t[1]
t[0]
p+3
p t
*(p+3) p[3]
t[3] *(t+3)
t ≡ &t[0] *(p+3) p[3]
7/02/10 5-15 ANSI C90-C99
7/02/10 ANSI C90-C99 5-16
Tableaux et pointeurs Confusion tableau/pointeur (2)
Passage de tableau en paramètre de fonction En C, les paramètres sont passés
par valeur Il n’y a aucune exception à cette
règle Les tableaux sont passés par
référence
Le paradoxe apparent est en fait résolu par la confusion tableau/pointeur
void f(int n, int *tab); void g(int n, int tab[]); void h(int n, int tab[n]);
int t[10]; f(10, t); // f(10, &t[0]); g(10, t); // g(10, &t[0]); h(10, t); // h(10, &t[0]);
7/02/10 5-16 ANSI C90-C99
7/02/10 ANSI C90-C99 5-17
Tableaux et pointeurs Confusion tableau/pointeur (3)
Chaînes de caractères Les chaines de caractères sont représentées comme des
tableaux de char La confusion tableau/pointeur conduit à identifier les chaînes de
caractères à des pointeurs sur caractères (char *)
char *strcpy(char *dest, const char *org); char *s1 = "hello"; char s[] = "hello";
7/02/10 5-17 ANSI C90-C99
7/02/10 ANSI C90-C99 5-18
Tableaux et pointeurs Confusion tableau/pointeur (4)
Exemple d'utilisation de pointeurs pour manipuler des chaînes de caractères Code compact, très efficace
void strcat(char *s1, char *s2) { while (*s1) s1++; while (*s1++ = *s2++) {} }
void strcmp(char *s1, char *s2) { for ( ; *s1 == *s2; s1++, s2++) if (*s1 == '\0') return 0; return *s1 - *s2; }
7/02/10 18 ANSI C90-C99 7/02/10 5-18 ANSI C90-C99
7/02/10 ANSI C90-C99 5-19
Tableaux et pointeurs Confusion tableau/pointeur (5)
Différences entre tableaux et pointeurs Malgré la confusion tableau/pointeur, les pointeurs et les
tableaux sont différents en ce qui concerne l’allocation mémoire int t[10]; int *pi; assert(sizeof(t) == 10*sizeof(int)); // 40 assert(sizeof(pi) == sizeof(int *)); // 4
char *pc1 = "hello"; char pc2[] = "hello"; assert(sizeof(pc1) == sizeof(char *)); // 4 assert(sizeof(pc2) == 6); // 5 plus nul assert(sizeof("hello") == 6); // 5 plus nul
7/02/10 5-19 ANSI C90-C99
7/02/10 ANSI C90-C99 5-20
Tableaux et pointeurs Tableau de pointeurs (1)
Déclaration d’un tableau de pointeurs int *t[10]; char *ts[] = { "hi", "hello", "hola" };
t est un tableau de 10 pointeurs sur caractères ts est un tableau de (3) pointeurs sur caractère, chaque
pointeur initialisé à l'adresse d'une chaîne constante
int i = 3; t[j] = &i; *t[j] = 13; if (ts[j][0] == 'h') ...
7/02/10 5-20 ANSI C90-C99
7/02/10 ANSI C90-C99 5-21
Tableaux et pointeurs Tableau de pointeurs (2)
À cause de la confusion tableau/pointeur , un nom de tableau de pointeurs est un pointeur sur son premier élément, lui-même un pointeur donc, est un double pointeur
int *t[10]: int **ppi = t; // t == &t[0] t[j] = &i; ppi[j] = &i; *(ppi + j) = &i; *t[j] = 3; *ppi[j] = 3; **(ppi + j) = 3;
7/02/10 5-21 ANSI C90-C99
7/02/10 ANSI C90-C99 5-22
Tableaux et pointeurs Tableau de pointeurs (3)
Tableau de pointeur et tableau multi-dimensionnel Les pointeurs étant indexables, un tableau de pointeur et un
tableau bi-dimensionnel peuvent se manipuler de la même manière char *days[] = { "lundi", "mardi", … }; char jours[][10] = { "lundi", "mardi", … };
days est un tableau de (7) pointeurs jours est une matrice de 7x10 caractères Cependant jours et days sont tous deux des char **
days[2] et jours[2] désignent tous les deux "mercredi" days[2][0] et jours[2][0] désignent tous les deux 'm'
7/02/10 5-22 ANSI C90-C99
Tableaux et pointeurs Tableau de pointeurs (4)
Tableau de pointeur et tableau multi-dimensionnel (suite)
char *days[7]; char jours[7][10];
L'organisation mémoire de days et jours est différente...
Comme leur sizeof sizeof(days) vaut 7*sizeof(char *) (28)
sizeof(jours) vaut 70
Noter que argv est du même type que days :
char *argv[]
days
7/02/10 ANSI C90-C99 5-23
lundi\0
mardi\0
mercredi\0
jeudi\0
vendredi\0
samedi\0
dimanche\0 lundi\0
mardi\0
mercredi\0
jeudi\0
vendredi\0
samedi\0
dimanche\0
jours 7/02/10 5-23 ANSI C90-C99
7/02/10 ANSI C90-C99 5-24
Tableaux et pointeurs Tableau de pointeurs (5)
Exemple de manipulation de tableau de pointeurs : echo main(int argc, char *argv[]) { for (i = 1; i < argc; i++) printf("%s ", argv[i]); putchar('\n'); }
main(int argc, char **argv) { while (--argc) printf("%s ", *++argv); putchar('\n'); }
Une forme très idiomatique !
7/02/10 5-24 ANSI C90-C99
7/02/10 ANSI C90-C99 5-25
Allocation dynamique de mémoire Motivation
Allouer des objets dont le nombre n'est pas connu à la compilation
Allouer un tableau dont le nombre d'éléments n'est connu qu'à l'exécution En C99, si le tableau est local à
une fonction on peut utiliser les tableaux à dimension variable
Mais si le tableau doit être global à plusieurs fonctions ou si l'on est en C90 ?
La solution est la fonction malloc
double *pt;
int main(int argc, char *argv[]) { int n = atoi(argv[1]); double t[n];
pt = malloc(n*sizeof(double)); // ...
}
7/02/10 25 ANSI C90-C99 7/02/10 5-25 ANSI C90-C99
7/02/10 ANSI C90-C99 5-26
Allocation dynamique de mémoire La famille malloc
Allocation à l'exécution d'un espace mémoire de taille donnée La taille peut être une variable La zone allouée n'est accessible
qu'au travers de pointeurs Si il n'y a plus de mémoire
disponible, les fonctions retournent le pointeur nul
Attention : free et realloc p ne doit pas être le pointeur nul la valeur de p doit avoir été
obtenue par appel de malloc, calloc ou realloc
void *malloc(size_t sz); Alloue une zone de taille sz Aucune intiailisation de la zone
void *calloc(size_t n, size_t sz);
Alloue une zone pour n éléments, chacun de taille sz
Initialise les éléments à 0 void *realloc(void *p, size_t new_sz);
Réalloue la zone allouée pour p avec la taille new_sz ; les éléments existants sont copiés
void free(void *p); Libère la zone allouée pour p
7/02/10 26 ANSI C90-C99 7/02/10 5-26 ANSI C90-C99
Pointeurs et structures
Opérateur de sélection -> (struct et union) struct Person { char name[20]; struct Date birthdate; }; struct Person msmith = { "Mary Smith", {13, 8, 1987 }}; struct Person *p = &msmith; struct Date d = (*p).birthdate; struct Date d = p->birthdate; int age = current_year - p->birthdate.year;
p->champ ≡ (*p).champ
7/02/10 5-27 ANSI C90-C99
Exemple d'utilisation de pointeurs Type récursif
Notion de type récursif Un type qui se définit à partir de lui-même Exemple : une liste simple
est soit vide soit composée d'une cellule suivie d'une liste
Ces types n'ont pas de représentation directe en C (ni en Java, ni en C++ d'ailleurs) on utilise des pointeurs pour les réaliser
7/02/10 5-28 ANSI C90-C99
Exemple d'utilisation de pointeurs Liste simple d'entiers (1)
1
3
3
5 NULL
phead
List_Cell val
next
phead->next->next->val
phead->next
7/02/10 5-29 ANSI C90-C99
Exemple d'utilisation de pointeurs Liste simple d'entiers (2)
Cellule de liste typedef struct List_Cell { int val; struct List_Cell *next; } Cell;
Addition d'un élément en tête de liste Cell *prepend(Cell *phead, int v) { Cell *pcell = malloc(sizeof(Cell)); pcell->val = v; pcell->next = phead; return pcell; }
7/02/10 5-30 ANSI C90-C99
Exemple d'utilisation de pointeurs Liste simple d'entiers (3)
Parcours de liste : recherche d'une valeur dans la liste
bool contains(const Cell *phead, int v) { for (Cell *pcell = phead; pcell != 0; pcell = pcell->next) { if (pcell->val == v) return true; } return false; }
7/02/10 5-31 ANSI C90-C99
Rôle du préprocesseur
Le préprocesseur agit sur toute unité de compilation (.c) avant la compilation proprement dite
Il effectue sur ce source des substitutions textuelles Inclusion de fichiers Définition de macros Compilation conditionnelle
Ces substitutions sont controlées par des directives Les directives commencent toutes par # comme premier
caractère de la ligne
7/02/10 ANSI C90-C99 2
Inclusion de fichier source Directive #include (1)
#include <nom_de_fichier> #include "nom_de_fichier"
Le nom_de_fichier peut être absolu ou relatif Si il est relatif
la première forme le recherche dans une liste pré-définie de répertoires (dont /usr/include en général)
la seconde forme le recherche d'abord dans le répertoire courant puis, en cas d'échec, dans la même liste prédéfinie de répertoires
Le contenu du fichier inclus remplace la ligne qui l'inclut
7/02/10 ANSI C90-C99 3
Inclusion de fichier source Directive #include (2)
#include <stdio.h> Inclusion du fichier standard stdio.h (très vraisemblablement
/usr/include/stdio.h) #include "mylist.h"
Inclusion du fichier mylist.h du répertoire courant #include "../List/mylist.h"
Inclusion du fichier mylist.h du répertoire "frère" List #include <sys/time.h>
Inclusion du fichier time.h du sous-répertoire sys d'un des répertoires prédéfinis (/usr/include/sys/time.h ?)
#include </usr/X11R6/include/X11.h> Inclusion du fichier /usr/X11R6/include/X11.h (nom
absolu) ; comportement identique avec "…" 7/02/10 ANSI C90-C99 4
Inclusion de fichier source Modification des répertoires #include
La liste de répertoires explorés par #include est prédéfinie à l'installation
Option –I de la commande de compilation
gcc –I $HOME/include –I /usr/local/include –c prog.c
insère $HOME/include et /usr/local/include en tête des répertories explorés par #include
les répertoires standards (e.g., /usr/include) seront quand même explorés en cas d'échec
7/02/10 ANSI C90-C99 5
Définition de macro Directive #define sans paramètre (1)
Syntaxe #define ident˽chaîne de remplacement
ident est un identificateur valide la chaîne de remplacement est un texte quelconque qui
se termine à la fin de la ligne peut contenir des espaces commence au premier espace suivant ident (˽)
L'identificateur ident est remplacé dans le texte du programme par la chaîne indiquée sauf quand il figure dans un commentaire ou une constante
caractère littérale de type caractère ou chaîne de caractères 7/02/10 ANSI C90-C99 6
Définition de macro Directive #define sans paramètre (2)
Définition de constantes #define EOF -1 #define N 10 #define N2 N * N // ... int t[N]; // → int t[10]
double u[N2]; // → double u[N * N] → double u[100]
printf("Valeur de N2: %d\n", N2); // → printf("Valeur de N2: %d\n", 100)
7/02/10 ANSI C90-C99 7
Définition de macro Directive #define sans paramètre (3)
Autres utilisations… déconseillées #define if if ( #define then ) { #define else ;} else { #define endif ;} // ... if a == 0 then x = 1 else x = 0; y++ endif
7/02/10 ANSI C90-C99 8
Définition de macro Directive #define sans paramètre (4)
Macros prédéfinies : C90 et C99 __LINE__ numéro de la ligne courante __FILE__ nom du fichier courant __DATE__ date courante __TIME__ heure courante __STDC__ défini pour un compilateur C90
Macros prédéfinies : C99 uniquement __STDC_VERSION__ version de la norme C (199901L)
7/02/10 ANSI C90-C99 9
Définition de macro Définition en commande de compilation
Option –D de la commande de compilation Permet de définir une macro… sans changer le fichier source
Example gcc -c -DMAXBUF=150 –DSYSTEM=linux -DDEBUG buffer.c équivalent à débuter buffer.c par
#define MAXBUF 150 #define SYSTEM linux #define DEBUG
7/02/10 10 ANSI C90-C99
Définition de macro Directive #define avec paramètre (1)
Syntaxe #define ident(x1, x2, …, xn)˽remplacement la chaîne de remplacement est un texte quelconque qui peut
contenir les identificateurs xi il ne doit pas y avoir d'espace entre ident et (
Un texte de la forme ident(a1, a2, …, an) où les ai sont des expressions quelconques, est remplacé par la chaîne indiquée après substitution de xi par ai sauf quand il figure dans un commentaire ou une constante
caractère littérale de type caractère ou chaîne de caractères
7/02/10 ANSI C90-C99 11
Définition de macro Directive #define avec paramètre (2)
Fonctions en ligne #define getchar() getc(stdin) #define putchar(c) putc(c, stdout)
#define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b))
while ((c = getchar()) != EOF) m = min(m, c);
// → while ((c = getc(stdin)) != (-1)) // m = ((m) < (c) ? (m) : (c));
7/02/10 ANSI C90-C99 12
Définition de macro Directive #define avec paramètre (3)
Danger des macros Substitution purement textuelle
#define bad_max(a, b) a > b ? a : b x = 2 + bad_max(x, y); // → x = 2 + a > b ? a : b; // → x = (2 + a) > b ? a : b;
Risque d'évaluation multiple des arguments x = max(a--, b--); // → x = ((a--) > (b--) ? (a--) : (b--));
Risque de perte de performance x = max(a[i*3 + 2*j][k+1], b[2*i]; // → x = ((a[i*3 + 2*j][k+1]) > (b[2*i]) ?
// (a[i*3 + 2*j][k+1]) : (b[2*i]));
7/02/10 13 ANSI C90-C99
Définition de macro Directive #define avec paramètre (4)
Danger des macros (suite) Pas de pointeur sur macro (mais pointeur sur fonction) Les macros sont toujours expansées en ligne
Fonctions inline de C99 Ce sont de vraies fonctions On peut avoir des pointeurs dessus Appel « atomique » Évaluation unique des arguments Le compilateur peut choisir de faire ou non l'expansion en ligne
Cependant, les macros à arguments sont utiles pour certaines opérations de nature «syntaxique »
7/02/10 ANSI C90-C99 14
Définition de macro Opérateur de concaténation ##
L'opérateur ## permet de concaténer un paramètre de macro avec une autre chaîne (ou un autre paramètre)
#define Positif(func) \ bool Positif_##func(double x) \ { \ double res = func(x); \ return res > 0; \ }
Positif(sin); // → int Positif_sin(double x) { ... } Positif(cos);
// → int Positif_cos(double x) { ... }
7/02/10 15 ANSI C90-C99
Définition de macro Opérateur de « stringification » #
L'opérateur # transforme le texte correspondant à un paramètre de macro en constante littérale de chaîne de caractères (c'est-à-dire met des doubles quotes autour !) #define Positif(func) \ bool Positif_##func(double x) \ { \ printf("Enter: %s\n", "Positif_" #func); \ double res = func(x); \ return res > 0; \ } Positif(cos); // → printf("Enter: %s\n", "Positif_" "cos"); // → printf("Enter: %s\n", "Positif_cos");
7/02/10 ANSI C90-C99 16
Définition de macro Portée d'une définition de macro
La portée de #define est l'unité de compilation courante à partir de la directive #define elle-même
Il est possible d'annuler une définition de macro à partir d'un certain point de l'unité de compilation
#undef DEBUG #undef MAX
7/02/10 ANSI C90-C99 17
Évaluation des macros
Avantages Elles permettent de modifier ou d'adapter la syntaxe du langage Elles permettent de définir des fonctions en ligne
Inconvénients Elles permettent de modifier ou d'adapter la syntaxe du langage Elles permettent de définir des fonctions en ligne
7/02/10 ANSI C90-C99 18
Compilation conditionnelle Directive #if
#if expression_statique lignes à inclure si expression_statique vraie #else lignes à inclure si expression_statique fausse #endif
expression_statique est une expression (entière) qui doit être évaluable à la compilation
la partie #else est évidemment optionnelle
7/02/10 ANSI C90-C99 19
Compilation conditionnelle Directives #ifdef/#ifndef (1)
#if defined(DEBUG) fprintf("entering %s\n", __func__); #endif
#ifdef DEBUG // ≡ #if defined(DEBUG) fprintf("entering %s\n", __func__); #endif
#ifndef DEBUG // ≡ #if ! defined(DEBUG) #define assert(x) #endif
7/02/10 ANSI C90-C99 20
Compilation conditionnelle Directives #ifdef/#ifndef (2)
#ifndef MAXSIZE #define MAXSIZE 1024 #endif
#if MAX > 1024 #error MAX too big #else int buffer[MAX];
#endif
typedef struct { #if VAX || SUN int _cnt; unsigned char *_ptr;
#else unsigned char *_ptr;
#endif unsigned char *_base; // ...
} FILE;
7/02/10 ANSI C90-C99 21
Compilation conditionnelle Inclusion unique de fichier (1)
// fichier: A.h #ifndef _A_H_ #define _A_H_ struct A { // ...
}; #endif
7/02/10 ANSI C90-C99 22
// fichier: B.h #ifndef _B_H_ #define _B_H_ #include "A.h" struct B { struct A a; // ...
}; #endif // fichier: main.c
#include "A.h" #include "B.h" struct A a; struct B b; // ...
• Toujours protéger les fichiers d'entête en inclusion unique Double
définition de struct A !
Directives diverses
#error message Interrompt le traitement (et donc la compilation) avec
l'impression de message sur le flux d'erreur standard #pragma quelque chose
Commentaire ayant (peut-être) une signification pour certains compilateurs…
C99 définit quelques pragmas standards #line numéro
Fait croire au compilateur que le numéro de ligne est numéro Permet au compilateur de numéroter les lignes comme dans le
fichier source avant le prétraitement du préprocesseur 7/02/10 ANSI C90-C99 1-23
Exécution du préprocesseur
L'option –E du compilateur permet de n'exécuter que le préprocesseur et de récupérer le source pur C ainsi produit
Il est donc possible d'utiliser le préprocesseur indépendemment du lanage C pour d'autres langages qui n'ont pas de préprocesseur pour effectuer des substitutions ou des inclusions textuelles
7/02/10 ANSI C90-C99 24
7/02/10 ANSI C90-C99 2
Généralités sur les fonctions
Déclaration Notion de prototype
Spécification du nom de la fonction Spécification de la signature (type) de la fonction
type des arguments type de retour
Définition Spécification du corps de la fonction (un bloc)
Invocation (appel) Équivalent à une valeur du type de retour de la fonction
7/02/10 ANSI C90-C99 2
7/02/10 ANSI C90-C99 3
Généralités sur les fonctions Type de retour et type des arguments
Le type de retour et le type des arguments d'une fonction doivent être des types affectables Tout type scalaire : entier, réel, énumération, pointeur Toute instance de structure ou d'union
Le type de retour void indique l'absence de valeur retournée La fonction est en fait une procédure
Une liste d'argument réduite à void indique l'absence d'argument
7/02/10 ANSI C90-C99 3
7/02/10 ANSI C90-C99 4
Généralités sur les fonctions Passage des arguments (1)
Les arguments sont toujours passés par valeur En fait, copie de la valeur du paramètre effectif dans une
variable locale à la fonction correspondant au paramètre formel
Dans le cas des tableaux et des chaînes de caractères, c'est un pointeur sur le premier élément qui est passé Ce pointeur est passé par valeur Mais le tableau semble donc passé par adresse C'est une conséquence de la confusion tableau/pointeur
7/02/10 ANSI C90-C99 4
7/02/10 ANSI C90-C99 5
Généralités sur les fonctions Passage des arguments (2)
void f(int i, double x) { // corps de la fonction }
double a = 1.5;
f(3, a); { int i = 3;
double x = a; // corps de la fonction }
7/02/10 ANSI C90-C99 5
Paramètres effectifs
Copie de la valeur
Paramètres formels
7/02/10 ANSI C90-C99 6
Généralités sur les fonctions Passage des arguments (3)
Conséquence du passage par valeur Une fonction ne peut modifier directement la valeur d'un de ses
paramètres effectifs
void f(int i) { i++; // ... }
int a = 3; f(a);
7/02/10 ANSI C90-C99 6
Modification de la copie (variable locale)
Après l'appel, a vaut toujours 3
7/02/10 ANSI C90-C99 7
Déclaration d'une fonction Prototype
Spécification du nom et de la signature
Le type de retour void indique l'absence de valeur retournée La fonction est en fait une
procédure Une liste d'argument réduite à
void indique l'absence d'argument
L'ellipse ... indique un nombre et type variable d'arguments Elle ne peut figurer qu'en fin de
liste
int f1(int i, double x); int f2(int, double);
struct Person g1(struct Employee);
struct Person * g2(struct Employee *);
void h1(void); int h3(...); int h2(); // ⇔ h3(...)
int printf(const char *, ...):
7/02/10 ANSI C90-C99 7
7/02/10 ANSI C90-C99 8
Définition d'une fonction
double f1(int n, double x) { double p = 1.0;
while (n--) p *= x; return p;
}
L'en-tête vaut prototype Si des prototypes de la fonction ont été rencontrés avant, ils doivent
être compatibles entre eux et avec l'entête
Une fonction ne peut pas être définie dans un bloc Pas de fonction locale !
7/02/10 ANSI C90-C99 8
Nom des arguments formels En-tête de la fonction
Corps de la fonction : un bloc
7/02/10 ANSI C90-C99 9
Invocation d'une fonction (1)
Le nombre de paramètres effectifs doit correspondre à la signature
Le type d'un paramètre effectif doit être soit identique à celui du paramètre formel homologue soit convertible implicitement dans celui du paramètre formel
homologue
L'ordre d'évaluation des paramètres n'est pas spécifié L'appel d'une fonction est un expression dont le type est
celui de la valeur de retour Le retour est toujours par valeur
7/02/10 ANSI C90-C99 10
Invocation d'une fonction (2)
int f(int a, double x); int i, j; short int s; double y; struct Person lui;
i = f(3, 5.3); // OK : types exacts i = f(i, y); // OK : types exacts f(s, 2); // OK : s → int, 2 → 2.0, et valeur de retour ignorée
f(lui, 5.0); // NON : pas de conversion struct Person → int f(&lui, 5.0); // NON : pas de conversion pointeur → int
7/02/10 ANSI C90-C99 11
Invocation d'une fonction Instruction return
L'instruction return termine l'exécution de la fonction courante Si la fonction retourne une valeur, celle-ci doit être spécifiée
dans une expression suivant le return return x + 2 * y;
Il n'y a pas besoin de parenthèses autour de l'expression !
Après le retour de la fonction, les variables locales sont désallouées
7/02/10 ANSI C90-C99 12
Fonction et pointeur Fonction retournant un pointeur (1)
void *malloc(size_t); List_Cell *insert(List_Cell *, int);
struct Person *pp = malloc(sizeof(struct Person));
List_Cell *phead = 0; phead = insert(phead, 3); insert(phead, 2)->val = 17;
7/02/10 ANSI C90-C99 13
Fonction et pointeur Fonction retournant un pointeur (2)
Attention aux pointeurs qui ne pointent plus sur rien !
int *f(void) { int tmp = 3; // une variable locale // ... return &tmp; // les variable locales sont // désallouées en fin de bloc }
int *pi = f(); // pi ne pointe sur rien de raisonnable
7/02/10 ANSI C90-C99 14
Fonction et pointeur Pointeur en argument (1)
Modification de variables de l'appelant void swap(int *pa, int *pb) { int tmp = *pb; *pb = *pa; *pa = tmp; }
int a = 2, b = 4 swap(&a, &b); // maintenant a == 4 et b == 2
7/02/10 ANSI C90-C99 15
Fonction et pointeur Pointeur en argument (2)
Passage d'un objet de grande occupation mémoire Le passage par valeur (copie) serait très couteux Comme l'intention n'est pas de modifier l'objet dans l'appelant, il
faut passer un pointeur sur une constante void print_Person(const struct Person *p) { // ... }
Le compilateur détecte (et condamne) toute tentative de modification
7/02/10 ANSI C90-C99 16
Fonction et pointeur Pointeur en argument (3)
Pour mémoire, les tableaux (et chaînes de caractères) sont passés par pointeur
int strcmp(const char *, const char *); int f(int n, double t[n]); // C99
char h[] = {"hello"}; double t[] = {1, 2, 3, 4};
if (strcmp(h, "bye")) ... // passe h cad &h[0] // ainsi que l'adresse de "bye" int i = f(4, t); // passe t, cad &t[0]
7/02/10 ANSI C90-C99 17
Fonction et pointeur Pointeur sur fonction (1)
Il est possible de prendre l'adresse d'une fonction On obtient alors un pointeur sur (le code de) la fonction Ce pointeur est typé (par la signature de la fonction)
double (*ptrigo)(double); // ptrigo pointeur sur fonction à argument et résultat double double cos(double); // une telle fonction ptrigo = &cos;
Comme pour les tableaux, un nom de fonction isolé dans une expression équivaut à un pointeur sur cette fonction
ptrigo = cos;
7/02/10 ANSI C90-C99 18
Fonction et pointeur Pointeur sur fonction (2)
Lecture des déclarations de C int i; ⇒ dans une expression, i est un int
int *pi; ⇒ dans une expression, *pi est un int ⇒ donc pi est un pointeur sur int (puisque * est l'indirection)
int *ptab[10]; ⇒ dans une expression, *ptab[i] est un int (si i est un int) ⇒ donc ptab[i] est un pointeur sur int ⇒ donc ptab est un tableau de pointeurs sur int
7/02/10 ANSI C90-C99 19
Fonction et pointeur Pointeur sur fonction (3)
Lecture des déclarations de pointeurs sur fonction double (*ptrigo)(double); ⇒ dans une expression, (*ptrigo)(x) est un double
(si x est un double) ⇒ donc *ptrigo est une fonction à argument et résultat double ⇒ donc ptrigo est un pointeur sur fonction à argument et résultat double
double (*tabtrigo[])(double) = {sin, cos, tan}; ⇒ dans une expression, (*tabtrigo[i])(x) est un double
(si x est un double et i un int) ⇒ donc *tabtrigo[i] est une fonction à argument et résultat double ⇒ donc tabtrigo[i] est un pointeur sur fonction à argument et résultat
double ⇒ donc tabtrigo est un tableau de pointeurs sur fonction à argument et
résultat double ⇒ tabtrigo est lui-même de type double (**[])(double)
7/02/10 ANSI C90-C99 20
Fonction et pointeur Pointeur sur fonction (4)
Utilisation des pointeurs sur fonction Utilisation conforme à la définition
double (*ptrigo)(double) = cos; double (*tabtrigo[])(double) = {sin, cos, tan};
double x = (*ptrigo)(PI); // cos(PI) x = (*tabtrigo[1])(PI); // cos(PI)
Forme raccourcie, mais commode ! x = ptrigo(PI); // cos(PI) x = tabtrigo[1](PI); // cos(PI)
7/02/10 ANSI C90-C99 21
Fonction et pointeur Pointeur sur fonction (5)
Pointeur sur fonction en argument et retour de fonction double (*f())(double);
f est une fonction sans argument, retournant un pointeur sur une fonction à argument et résultat double double x = (*f())(3.5); x = f()(3.5); // forme raccourcie
double (*deriv(int n, double (*f)(double)))(double); deriv est une fonction à deux arguments retournant un pointeur sur une
fonction à argument et résultat double ; le premier argument est un int, le second un pointeur sur une fonction à argument et résultat double double (*pf)(double) = deriv(1, cos); x = (*deriv(1, cos))(PI); x = deriv(1, cos) (PI);
7/02/10 ANSI C90-C99 22
Fonction et pointeur Pointeur sur fonction (6)
On peut bien sûr faire des typedef de pointeurs sur fonction
typedef double (*DOUBLE2DOUBLE)(double); DOUBLE2DOUBLE est synonyme du type pointeur sur une
fonction à argument et résultat double
DOUBLE2DOUBLE pf = cos; pf(PI);
DOUBLE2DOUBLE deriv(int n, DOUBLE2DOUBLE f); pf = deriv(1, cos);
7/02/10 ANSI C90-C99 23
La fonction main Prototype
C'est la fonction par laquelle commence l'exécution d'un programme C
Son prototype est imposé parmi int main(); int main(int argc, char *argv[]); int main(int argc, char *argv[], char *envp[]);
argc et le tableau de chaînes de caractères argv correspondent aux arguments de la ligne de commande
argc est la dimension du tableau argv
argv[0] est toujours le nom de la commande (donc argc > 0)
argv[1], argv[2], ..., argv[argc-1] sont les arguments positionnels
7/02/10 ANSI C90-C99 24
La fonction main Valeur de retour
La valeur de retour de main est un entier qui sert de code de retour du programme Par convention, 0 indique une terminaison normal
L'instruction return n; termine le main et donc le programme en transmettant la valeur de l'expression n comme code de retour
Sous Unix, ce code de retour est consultable depuis le shell par la variable $? par les instruction conditionnelles du shell (if, while, etc.)
7/02/10 ANSI C90-C99 25
La fonction main Exemple de la commande echo
#include <stdio.h> #include <stdbool.h>
int main(int argc, char **argv) { bool linebrk = true; int i; for (i = 1; i < argc && argv[i][0] == '-'; ++i) { switch (argv[i][1]) { case 'n': // option –n nolinebrk = false; break; case ... : // ... autres options default : fprintf(stderr, "Option inconnue..."); return 1; } } for ( ; i < argc; ++i) printf("%s ", argv[i]); if (linebrk) putchar('\n'); return 0; }
7/02/10 ANSI C90-C99 2
Contenu
Compilation séparée, unité de compilation Déclaration et définition, ODR Nommage des objets Durée de vie et visibilité des objets Organisation des programmes
Programmation modulaire Vers les types abstraits
7/02/10 ANSI C90-C99 2
7/02/10 ANSI C90-C99 3
Compilation séparée
7/02/10 ANSI C90-C99 3
f1.c f1.o
a.out
compilateur
gcc f1.c f2.c f3.c
pré- processeur
compilateur pré- processeur
compilateur pré- processeur
f2.c
f3.c
f2.o
f3.o
bibliothèques utilisateur
bibliothèque standard
éditeur de liens
7/02/10 ANSI C90-C99 4
Compilation séparée Unité de compilation (1)
Le source d'un programme C est constitué d'une ou plusieurs unités de compilation
Une unité de compilation correspond (en général) à un fichier .c ainsi que tout ce que ce fichier peut inclure (#include)
directement ou non
Chaque unité de compilation est compilée séparément par une exécution différente du compilateur C elle doit donc contenir toute l'information nécessaire et suffisante
pour que le compilateur puisse faire son travail
7/02/10 ANSI C90-C99 5
Compilation séparée Unité de compilation (2)
Une unité de compilation est une suite de directives au préprocesseur
éliminées par l'action du préprocesseur lui-même
de définitions de type enum, struct, union, typedef
de déclarations ou définitions de variables ou de constantes de fonctions
7/02/10 ANSI C90-C99 6
Déclaration et définition One Definition Rule (ODR)
Déclaration : spécifie le nom de l'objet et son type Rien n'est alloué, aucune initialisation n'est possible Dans le cas d'une fonction, ceci correspond à un prototype
Définition : correspond à l'allocation de l'objet Une définition de constante ou de variable peut comporter une
initialisation Dans le cas d'une fonction, la définition fournit le corps Une définition vaut déclaration
One Definition Rule (ODR) Dans tout le programme il doit y avoir une seule définition de
chaque objet En revanche il peut y avoir autant de déclarations que l'on
souhaite, du moment qu'elles sont compatibles entre elles et avec la définition
7/02/10 ANSI C90-C99 7
Nommage des objets
Quatre espaces de nommage indépendants 1. noms de variables, constantes (const), fonctions, types
(typedef) et valeurs des constantes des types énumérés 2. étiquettes (goto) 3. tags des structures, unions et énumérations 4. noms de champs des structures et unions
Ce dernier espace est en fait un ensemble d'espaces indépendants, chacun étant propre à chaque structure ou union
Les variables du préprocesseur ne sont pas prises en compte ici
7/02/10 ANSI C90-C99 8
Durée de vie et visibilité
La durée de vie détermine l'existence d'un objet pendant l'exécution du programme C'est une propriété intrinsèque à
l'objet Elle correspond au mode
d'allocation mémoire (C dit la classe d'allocation)
Elle n'a de sens que pour les variables et constantes (const) Les fonctions existent de manière
permanente pendant l'exécution Les types n'ont pas d'existence à
l'exécution
La visibilité détermine les zones du programme où l'objet est accessible (par son nom) Elle est liée au nom utilisé pour
désigner l'objet Elle s'applique à tous les noms
manipulés par le compilateur
Attention En C un même objet peut être
désigné par plusieurs « noms » (aliasing)
La visibilité dépend du nom utilisé
7/02/10 ANSI C90-C99 9
Durée de vie et visibilité des données Durée de vie, classes d'allocation
Trois durées de vie/classes d'allocation (variables, constantes) 1. Allocation automatique
La durée de vie est celle d'un bloc 2. Allocation statique
La durée de vie est la durée d'exécution du programme Les objets correspondants sont automatiquement détruits en fin de
programme 3. Allocation dynamique
La durée de vie (création et destruction) est de la responsabilité du programmeur (e.g., malloc et free)
Les objets correspondants ne sont accessibles qu'à travers des pointeurs Ce type d'allocation n'est donc pas supporté directement par le
langage, mais il est commode de le mentionner ici
7/02/10 ANSI C90-C99 10
Durée de vie et visibilité des données Visibilité d'un nom
Deux zones de visibilité Visibilité locale
Le nom n'est visible que dans un bloc Visibilité globale
Le nom est visible dans toute l'unité de compilation Ceci inclut tous les fichiers inclus après la déclaration du nom
Cas de la visibilité globale Nom privé
Le nom n'est visible que dans l'unité de compilation Nom externe
Le nom est visible dans toutes les unités de compilation qui en comportent une déclaration (déclaration d'externe)
7/02/10 ANSI C90-C99 11
Durée de vie et visibilité des données Relation entre durée de vie et visibilité
Relation durée de vie/visibilité pour variables/constantes
Allocation automatique Allocation statique Allocation dynamique
Visibilité locale (bloc)
Variable/constante locale automatique (auto, register) Paramètres de fonction
Variable/constante locale statique de bloc (variable rémanente) static
La visibilité de ces objets (variables/constantes) est
celle des pointeurs qui permettent d'y accéder
Visibilité globale (unité de
compilation)
Variable/constante privée à l'unité de compilation static
Variable/constante externe, potentiellement visible dans tout le programme extern (déclaration)
7/02/10 ANSI C90-C99 12
Durée de vie et visibilité des données Variables locales
int f(int n, double x) { int i = 0; double y; static int ncalls = 0; // ... ncalls++; // nombre appels cumulés }
Variables locales automatiques : n, x, i, y Variables locales statiques (rémanentes) : ncalls
Pour une variable locale, pas de déclaration qui ne soit pas une définition
7/02/10 ANSI C90-C99 13
Durée de vie et visibilité des données Variables globales privées (1)
static int st1 = 0; // définition static double xst2; // déclaration static char c; // définition
int f(int n, double x) { // ... }
static double xst2 = 3.0; // définition
int g(void) { // ... }
7/02/10 ANSI C90-C99 14
Durée de vie et visibilité des données Variables globales privées (2)
/* fichier f2.c */ #include "incl.h" static int st; // ...
/* fichier f2.c */ #include "incl.h" static double st; // ...
/* fichier incl.h */ static short int si;
Deux variables privées
si et st Deux variables privées
si et st Aucune relation d'aucune sorte entre les deux st, ni entre les deux si
7/02/10 ANSI C90-C99 15
Durée de vie et visibilité des données Variables globales externes (1)
/* fichier f2.c */ extern int ext1; // décl. extern double ext2 = 3.0; // interdit double ext2 = 3.0; // OK
void f(void) { ext1 = 3; // util. } // ...
/* fichier f2.c */ int ext1 = 5; // déf.
void g(void) { if (ext1 == 0) ...; } // ...
7/02/10 ANSI C90-C99 16
Durée de vie et visibilité des données Variables globales externes (2)
/* fichier f2.c */ #include "incl.h"
void f(void) { ext = 3; } // ...
/* fichier f2.c */ #include "incl.h" int ext = 5; // déf.
void g(void) { if (ext == 0) ...; } // ...
/* fichier incl.h */ extern int ext; // décl.
7/02/10 ANSI C90-C99 17
Durée de vie et visibilité des données Initialisation par défaut des données
Allocation automatique Pas d'initialisation par défaut
Allocation statique Initialisation par défaut à 0
'\0' pour char, NULL pour pointeurs Cette valeur n'est pas toujours adéquate
Allocation dynamique calloc : initialisation à 0 malloc, realloc : pas d'initialisation
7/02/10 ANSI C90-C99 18
Durée de vie et visibilité des fonctions
En C les fonctions ont une durée de vie permanente (statique) Pas de fonction locale
Leur visibilité est globale Elles peuvent être privées (static) ou externes Elles sont externes par défaut
7/02/10 ANSI C90-C99 19
Durée de vie et visibilité Synthèse (1)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... }
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... }
7/02/10 ANSI C90-C99 20
Durée de vie et visibilité Synthèse (2)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... } // ...
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... } Visibilité du nom v
7/02/10 ANSI C90-C99 21
Durée de vie et visibilité Synthèse (3)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... } // ...
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... } Visibilité du nom vv
7/02/10 ANSI C90-C99 22
Durée de vie et visibilité Synthèse (4)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... } // ...
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... } Visibilité des variables static
7/02/10 ANSI C90-C99 23
Durée de vie et visibilité Synthèse (5)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... } // ...
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... } Visibilité des fonctions externes
7/02/10 ANSI C90-C99 24
Durée de vie et visibilité Synthèse (6)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... } // ...
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... } Visibilité des fonctions externes
7/02/10 ANSI C90-C99 25
Durée de vie et visibilité Synthèse (7)
int v = 2; int vv; int f1(int x, int y) { extern double g(void); int z; // ... } static double z; double f2(int x) { register int i; auto int v; // ... } // ...
extern int v; static int f3(int x) { double cos(double); static int w; extern int vv; // ... } static void f4(void) { // ... } static int z[10]; extern int vv; extern f1(int, int); double g(void) { // ... } Visibilité des fonctions static
7/02/10 ANSI C90-C99 26
Durée de vie et visibilité Règles de visibilité particulières
Les étiquettes (goto) ont une visibilité réduite à la fonction où elles sont définies
Les noms de type (typedef), les tags de structure, union ou énumération, les constantes littérales des énumérations ont une visibilité qui est la même que leur définition (locale ou globale)
enum Color {RED, GREEN, BLUE}; // global void f(void) { struct foo {int i; double x}; // local typedef struct foo Foo; enum E {E1, E2}; // ... }
7/02/10 ANSI C90-C99 27
Programmation modulaire en C
Un module regroupe des données et des fonctions partageant ces données
Un module représente une entité logique et autonome du programme Forte cohésion interne Faible couplage externe
L'interface du module contient l'information nécessaire et suffisante pour utiliser le module
Le corps contient les détails internes de réalisation
interface (spécification) module.h
information pour les clients du module
corps (implémentation) module.c
détails internes de réalisation du module
7/02/10 ANSI C90-C99 28
Programmation modulaire en C Exemple de module
// Pile d'entiers : interface // Fichier : Stack.h #ifndef _STACK_H_ #define _STACK_H_
void stack_init(size_t); void stack_push(int); int stack_pop(void); bool stack_is_full(void); bool stack_is_empty(void);
#endif
// Pile d'entiers : corps // Fichier : Stack.c #include "Stack.h"
static int *stack; static int top = 0; static size_t size;
void stack_init(size_t sz) { size = sz; stack = malloc(sz*sizeof(int)); } // ...
7/02/10 ANSI C90-C99 29
Programmation modulaire en C Organisation modulaire
stack.h stack.c
main.c
fifo.h fifo.c
list.h list.c
mylib.h mylib.c
#include #include
#include #include
Programmation modulaire en C Organisation modulaire : Makefile (1)
CC = gcc CFLAGS = -g –std=c99 –Wall LFLAGS = CCOMP = $(CC) $(CFLAGS)
main : main.o stack.o fifo.o list.o mylib.o $(CC) $(LFLAGS) –o main main.o stack.o fifo.o list.o mylib.o
main.o : stack.h fifo.h list.h main.c $(CCOMP) –c main.c stack.o : stack.h stack.c $(CCOMP) –c stack.c fifo.o : fifo.h list.h mylib.h fifo.c $(CCOMP) –c fifo.c list.o : list.h list.c $(CCOMP) –c list.c mylib.o : mylib.h mylib.c $(CCOMP) –c mylib.c
Programmation modulaire en C Organisation modulaire : Makefile (2)
CC = gcc CFLAGS = -g –std=c99 –Wall LFLAGS =
main : main.o stack.o fifo.o list.o mylib.o $(CC) $(LFLAGS) –o main main.o stack.o fifo.o list.o mylib.o
clean : main -rm *.o
realclean : -rm *.o -rm main
main.o : stack.h fifo.h list.h stack.o : stack.h fifo.o : fifo.h list.h mylib.h list.o : list.h mylib.o : mylib.h
7/02/10 ANSI C90-C99 32
Programmation modulaire en C Type abstrait (1)
// Pile d'entiers : interface // Fichier : Stack.h #ifndef _STACK_H_ #define _STACK_H_
void stack_init(size_t); void stack_push(int); int stack_pop(void); bool stack_is_full(void); bool stack_is_empty(void);
#endif
// Pile d'entiers : corps // Fichier : Stack.c #include "Stack.h"
static int *stack; static int top = 0; static size_t size;
void stack_init(size_t sz) { size = sz; stack = malloc(sz*sizeof(int)); } // ...
Programmation modulaire en C Type abstrait (2)
Un module tel que Stack représente un objet en exemplaire unique car la structure de données est elle-même en exemplaire unique
Si l'on veut manipuler plusieurs piles dans le même programme chaque pile doit posséder sa propre structure de données les fonctions doivent prendre un paramètre indiquant la pile sur
laquelle opérer
⇒ type abstrait
7/02/10 ANSI C90-C99 33
7/02/10 ANSI C90-C99 34
Programmation modulaire en C Type abstrait (3)
// Pile d'entiers : interface // Fichier : Stack.h #ifndef _STACK_H_ #define _STACK_H_
typedef struct { int *stack; int top; size_t size; } Stack;
void stack_init(Stack *, size_t); void stack_push(Stack *, int); int stack_pop(Stack *); bool stack_is_full(const Stack *); bool stack_is_empty(const Stack *;
#endif
// Pile d'entiers : corps // Fichier : Stack.c #include "Stack.h"
void stack_init(Stack *st, size_t sz) { st->size = sz; st->stack = malloc(sz*sizeof(int)); st->top = 0; }
void stack_push(Stack *st, int a) { st->stack[st->top++] = a; }
// ...
Programmation modulaire en C Type abstrait (4)
// Pile d'entiers : utilisation (main) // Fichier : main_Stack.c
#include "Stack.h"
int main() { Stack st; stack_init(&st, 10); stack_push(&st, 3); // ... }
7/02/10 ANSI C90-C99 35
7/02/10 ANSI C90-C99 2
Contenu
Panorama des fonctions de la bibliothèque standard Environnement de développement
7/02/10 ANSI C90-C99 2
Bibliothèque standard de C99
Ensemble de fichiers .h + archive Disponibles dans le chemin de recherche de #include
#include <stdlib.h>
Édition de liens par défaut avec la bibliothèque C (libc.a ou libc.so)
Documentation Sous Unix/Linux, pages de manuel
man string.h man strcpy
Utiliser une interface graphique (info, KDE Help Desk…) 7/02/10 ANSI C90-C99 3
Bibliothèque standard de C99 Définitions générales (1)
<stddef.h> Définitions générales (NULL, size_t, wchar_t…)
<stdbool.h> Type booléen (bool, true, false)
<limits.h> Propriétés des entiers dépendant de l'implémentation
<float.h> Propriétés des réels dépendant de l'implémentation
<stdint.h> Types entiers à représentation garanties (int32_t, int_least32_t…)
7/02/10 ANSI C90-C99 4
Bibliothèque standard de C99 Définitions générales (2)
<stdlib.h> Définitions générales • Macros utiles: NULL, EXIT_SUCCESS, EXIT_FAILURE… • Génération aléatoire : rand, srand… • Fonctions système : exit, abort, system… • Conversions chaînes-nombres : atoi, atof… • Allocation mémoire : malloc, free… • Utilitaires généraux : abs, qsort…
7/02/10 ANSI C90-C99 5
Bibliothèque standard de C99 Chaînes de caractères
Convention : les chaines sont terminées par le caractère nul ('\0') Les fonctions de bibliothèques exigent cette propriété Celles pour lesquelles cela a du sens l'imposent Cette convention ne s'applique pas aux opérations directes sur
la mémoire (e.g., memcpy, memcmp…) Deux jeux de fonctions
Pour chaînes mono-octets (ascii, iso-latin-1…) Préfixe str
Pour chaînes multi-octets (unicode) Préfixe wcs
7/02/10 ANSI C90-C99 6
Bibliothèque standard de C99 Chaînes de caractères mono-octets
<string.h> Manipulation des chaînes mono-octets Les fonctions ont le préfixe str • Copie : strcpy, strncpy… • Concaténation : strcat, strncat • Comparaison : strcmp, strncmp, strcoll… • Recherche de caractères : strchr, strrchr, strstr… • Découpage (tokenization) : strtok • Copie mémoire : memcpy, memmove, memcmp…
<ctype.h> Classification des caractères mono-octets • Type de caractère : isalpha, isnum, ispunct, islower… • Changement de casse : toupper, tolower
7/02/10 ANSI C90-C99 7
Bibliothèque standard de C99 Chaînes de caractères multi-octets
<wchar.h> Manipulation des chaînes multi-octets Les fonctions ont le préfixe wcs • Copie : wcscpy, wcsncpy… • Concaténation : wcscat, wcsncat • Comparaison : wcscmp, wcsncmp, wcscoll… • Recherche de caractères : wcschr, wcsrchr, wcsstr… • Découpage (tokenization) : wcstok • Opération mémoire : wmemcpy, wmemmove, wmemcmp… • Conversion mono-multi octets
<wctype.h> Classification des caractères multi-octets • Type de caractère : iswalpha, iswnum, iswpunct, iswlower… • Changement de casse : towupper, towlower
7/02/10 ANSI C90-C99 8
Bibliothèque standard de C99 Entrées-Sorties (1)
E/S avec buffer dans l'espace du processus utilisateur Flux d'entrée-sortie représentés par un pointeur sur FILE
(FILE *) Flux prédéfinis : stdin, stdout, stderr Autres flux
FILE *fp = fopen("foo", "r"); fprintf(fp, "%s\n", "hello !"); fclose(fp);
E/S séquentielle, avec accès aléatoire E/S formatées ou binaires 7/02/10 ANSI C90-C99 9
Bibliothèque standard de C99 Entrées-Sorties (2)
<stdio.h> E/S mono-octets • Ouverture/fermeture : fopen, fclose… • E/S par caractère: fget, fput, getchar… • E/S par ligne: fgets, fputs… • E/S formatées : printf, fprintf, scanf, fscanf… • E/S formatées en mémoire : sprintf, sscanf • Accès direct : fseek, rewind • E/S binaires : fread, fwrite… • Manipulation de fichiers : rename, remove…
<wchar.h> Définition des E/S pour caractères multi-octets • E/S par caractère: fgetwc, fputwc… • E/S par ligne: fgetws, fputws… • E/S formatées : wprintf, fwprintf, wscanf, fwscanf… • E/S formatées en mémoire : swprintf, swscanf…
7/02/10 ANSI C90-C99 10
Bibliothèque standard de C99 Date et heure
<time.h> • Représentation date et heure : time_t, clock_t, struct tm… • Heure brute : time, clock, mktime • Opérations arithmétiques sur dates et heures : difftime • Conversion date et heure en chaîne : asctime, ctime • Formatage de date et heure : strftime • Conversion locale/gmt : gmttime, localtime
7/02/10 ANSI C90-C99 11
Bibliothèque standard de C99 Fonctions mathématiques
<math.h> Fonctions mathématiques usuelles Existent pour float, double, long double • Trigonométriques, hyperboliques, exponentielles • Arrondis
<complex.h> Définition des opérations sur nombres complexes • Types complexes : avec float, double, long double • Opérations usuelles pour float, double, long double
<tgmath.h> Forme générique des fonctions de <math.h> et <complex.h> s'adaptant automatiquement aux types des aguments
<fenv.h> Exceptions de calcul en virgule flottante
7/02/10 ANSI C90-C99 12
Bibliothèque standard de C99 Fonctions diverses
<assert.h> Assertions (programmation défensive) <errno.h> Numéros d'erreur <locale.h> Localisation <setjmp.h> goto non local <signal.h> Événements asynchrones <stdarg.h> Support des fonctions avec un nombre variable d'arguments
7/02/10 ANSI C90-C99 13
Voir cours Système