224
Le langage C ISO 9899 (C90 et C99) Jean-Paul Rigault Polytech’Nice Sophia Université de Nice-Sophia Antipolis [email protected]

Le langage C ISO 9899 (C90 et C99

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

Le langage C

Introduction

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

Le langage C

Premiers pas

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 1

Le langage C

Éléments du langage

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

Le langage C

Tableaux, structures et unions

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

Le langage C

Pointeurs

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 = &pi; 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

Le langage C

Préprocesseur

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

Le langage C

Fonctions

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; }

Le langage C

Structure des programmes

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

Le langage C

Bibliothèque standard Environnement de développement

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