Vous êtes sur la page 1sur 44

Guide Superu de programmation en langage C

Matthieu Herrb Version 2.0 Mars 1999

Centre National de la Recherche Scientique Laboratoire dAnalyse et dArchitecture des Syst`mes e

Copyright 1997-1999, Matthieu Herrb. Ce document peut tre imprim et distribu e e e gratuitement dans sa forme originale (comprenant la liste des auteurs). Sil est modi e ou que de des extraits sont utiliss ` lintrieur dun autre document, alors la liste des e a e auteurs doit inclure tous les auteurs originaux et celui (ou ceux) qui a (qui ont) modi e le document. Copyright 1997-1999, Matthieu Herrb. This document may be printed and distributed free of charge in its original form (including the list of authors). If it is changed or if parts of it are used within another document, then the author list must include all the original authors AND that author (those authors) who has (have) made the changes.

Table des mati`res e


I I.1 Quelques pi`ges du langage C e Fautes de frappe fatales . . . . . . . . . . . . . . . . . . . I.1.1 Mlange entre = et == . . . . . . . . . . . . . . . . e I.1.2 Tableaux ` plusieurs dimensions . . . . . . . . . . . a I.1.3 Oubli du break dans les switch . . . . . . . . . . . . I.1.4 Passage des param`tres par adresse . . . . . . . . . e Probl`mes de calcul sur les nombres rels . . . . . . . . . e e I.2.1 Egalit de rels . . . . . . . . . . . . . . . . . . . . e e I.2.2 Probl`mes darrondis . . . . . . . . . . . . . . . . . e I.2.3 Absence de dclaration des fonctions retournant des e Style des dclarations de fonctions . . . . . . . . . . . . . e Variables non initialises . . . . . . . . . . . . . . . . . . e Ordre dvaluation indni . . . . . . . . . . . . . . . . . e e Allocation dynamique de la mmoire . . . . . . . . . . . e I.6.1 Rfrence ` une zone mmoire non alloue . . . . . ee a e e I.6.2 Rfrence ` une zone mmoire libre . . . . . . . . ee a e ee I.6.3 Libration dune zone invalide . . . . . . . . . . . . e I.6.4 Fuites . . . . . . . . . . . . . . . . . . . . . . . . . Cha nes de caract`res . . . . . . . . . . . . . . . . . . . . e I.7.1 Dbordement dune cha de caract`res . . . . . . e ne e I.7.2 Ecriture dans une cha en mmoire statique . . . ne e Pointeurs et tableaux . . . . . . . . . . . . . . . . . . . . I.8.1 Assimilation dun pointeur et dun tableau statique I.8.2 Appel de free() sur un tableau . . . . . . . . . . . . Entres/sorties standard . . . . . . . . . . . . . . . . . . e I.9.1 Contrle des param`tres de printf et scanf . . . . . o e I.9.2 Lecture de cha nes de caract`res . . . . . . . . . . . e I.9.3 Lecture de donnes binaires . . . . . . . . . . . . . e Processeurs 64 bits . . . . . . . . . . . . . . . . . . . . . 3 6 6 7 7 8 9 9 9 10 10 11 12 12 13 13 13 14 15 15 15 16 17 17 17 17 18 18 19 19

I.2

I.3 I.4 I.5 I.6

I.7

I.8

I.9

I.10

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . doubles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

` TABLE DES MATIERES

I.10.1 Absence de dclarations des fonctions . . . . . . . . . . . . e I.10.2 Manipulation de pointeurs . . . . . . . . . . . . . . . . . . I.11 Pr-processeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . e II II.1 II.2 II.3 II.4 II.5 II.6 II.7 III Un peu dalgorithmique Introduction . . . . . . . . . . . . . . Allocation dynamique de la mmoire e Pointeurs . . . . . . . . . . . . . . . . Listes . . . . . . . . . . . . . . . . . . Ensembles . . . . . . . . . . . . . . . Tris et recherches . . . . . . . . . . . Cha nes de caract`res . . . . . . . . . e

20 20 20 22 22 23 24 24 24 25 25 27 28 30 30 31 32 32 32 32 33 34 35 35 37 37 39 39 40 40 41 41 42 43

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

Crer des programmes s rs e u III.1 Comment exploiter les bugs dun programme III.2 R`gles pour une programmation sre . . . . e u III.2.1 Eviter les dbordements . . . . . . . . e III.2.2 Se mer des donnes . . . . . . . . . . e e III.2.3 Traiter toutes les erreurs . . . . . . . . III.2.4 Limiter les fonctionnalits . . . . . . . e III.2.5 Se mer des biblioth`ques . . . . . . . e e III.2.6 Bannir les fonctions dangereuses . . . . III.3 Pour aller plus loin... . . . . . . . . . . . . . Questions de style IV.1 Commentaires et documentation IV.1.1 Commentaires . . . . . . . IV.1.2 Documentation . . . . . . IV.2 Typologie des noms . . . . . . . IV.3 Dclarations . . . . . . . . . . . e IV.4 Indentation . . . . . . . . . . . IV.5 Boucles . . . . . . . . . . . . . . IV.6 Expressions complexes . . . . . IV.7 Conversion de types . . . . . . . IV.8 Assertions . . . . . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

IV

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

Rfrences bibliographiques ee Index

Introduction
Ce document a pour but de rappeler certaines r`gles et techniques que tout le e monde conna pour dvelopper une application de taille ( srieuse ) en langage C. t e ( e ) Les sources dinformations sur le sujet sont nombreuses, cest pourquoi je pense que ce document est superu. En particulier, La Foire Aux Questions (FAQ) du forum Usenet comp.lang.c constitue une source dinformation beaucoup plus riche, mais en anglais. Elle est accessible par lURL : http://www.eskimo.com/~scs/C-faq/top.html Cette FAQ existe aussi sous forme de livre [1]. La bibliographie contient une liste dautres articles ou ouvrages dont la lecture vous sera plus protable. Si toutefois vous persistez ` vouloir lire ce document, a voici un aperu de ce que vous y trouverez : c Le premier chapitre fait un tour parmi les probl`mes les plus souvent rene contrs dans des programmes C. e Le deuxi`me chapitre donne quelques conseils sur le choix et le type dalgoe rithmes ` utiliser pour viter de rinventer la roue en permanence. a e e Le troisi`me chapitre sintresse ` laspect scurit informatique des algoe e a e e rithmes et de leurs implmentations, sachant que cet aspect doit tre intgr au e e e e plus tt dans lcriture dun programme. o e Enn, le quatri`me chapitre traite du style du code source : indentation, choix e des noms de variables, commentaires,... Il ne sagit pas dobligations ` respecter ` tout prix, mais suivre ces recommana a dations permettra de gagner du temps dans la mise au point dune application et facilitera sa maintenance.

Chapitre I Quelques pi`ges du langage C e

Le but de ce document nest pas de faire un cours de langage C. Il y a des livres pour a. Mais entre les bases du langage et la mise en uvre concr`te de c e ses fonctionnalits, il y a parfois quelques dicults. e e La plupart des erreurs dcrites ici ne sont pas dtectes ` la compilation. e e e a Certaines de ces erreurs conduisent systmatiquement ` un plantage du proe a gramme en cours dexcution ou ` un rsultat faux, alors que dautres conduisent e a e a ` des situations que la norme du langage C dnit comme ( comportements e ( indtermins )), cest-`-dire que nimporte quoi peut se produire, selon les choix e e a de programmation du compilateur ou du syst`me. e Parfois, dans ce cas, le programme en question ` lair de fonctionner correca tement. Une erreur ne se produira que dans certaines conditions, ou bien lorsque lon tentera de porter le programme en question vers un autre type de machine.

I.1

Fautes de frappe fatales

Cette section commence par attirer lattention du lecteur sur quelques erreurs dinattention qui peuvent tre commises lors de la saisie dun programme et qui e ne seront pas dtectes par la compilation mais produiront ncessairement des e e e erreurs plus ou moins faciles ` dtecter ` lexcution. a e a e

I.1. Fautes de frappe fatales

I.1.1

Mlange entre = et == e

Cette erreur est lune des plus frquentes, elle provient de la syntaxe du langage e combine ` linattention du programmeur. Elle peut tre tr`s dicile ` dtecter. e a e e a e Cest pourquoi, il est indispensable davoir le probl`me ` lesprit en permanence. e a Pour ceux qui ne sauraient pas de quoi il est question ici, rappelez-vous que x = 0 est une expression valide en C qui aecte ` x la valeur zro et qui retourne a e la valeur aecte, cest ` dire zro. Il est donc parfaitement lgal dcrire : e a e e e if (x = 0) { /* traitement ` lorigine */ a ... } else { /* traitement des autres valeurs */ ... } Malheureusement le traitement particulier de x = 0 ne sera jamais appel, et en e plus dans le traitement des x = 0 la variable x vaudra 0 ! Pour ceux qui ne lauraient pas vu, il fallait crire : e if (x == 0) { /* traitement ` lorigine */ a ... } else { /* traitement des autres valeurs */ ... } Certains sugg`rent dutiliser systmatiquement la construction suivante, qui e e a le mrite de provoquer une erreur ` la compilation si lon oublie lun des ( = ) : e a ( ) if (0 == x) . Cependant, ce probl`me nest pas limit au cas de la comparaison avec une e e constante. Il se pose aussi lorsque lon veut comparer deux variables.

I.1.2

Tableaux ` plusieurs dimensions a

En C les indices dun tableau ` plusieurs dimensions scrivent avec autant a e de paires de crochets quil y a dindices. Par exemple pour une matrice ` deux a dimensions on crit: e double mat[4][4];

Chapitre I. Quelques pi`ges du langage C e

x = mat[i][j]; Le risque derreur provient du fait que la notation mat[i,j] (qui est employe e dans dautres langages) est galement une expression valide en langage C. e

I.1.3

Oubli du break dans les switch

Noubliez pas le break ` la n de chaque case dans une instruction switch. Si a le break est absent, lexcution se poursuit dans le case suivant, ce qui nest en e gnral pas le comportement voulu. Par exemple : e e void print_chiffre(int i) { switch (i) { case 1: printf("un"); case 2: printf("deux"); case 3: printf("trois"); case 4: printf("quatre"); case 5: printf("cinq"); case 6: printf("six"); case 7: printf("sept"); case 8: printf("huit"); case 9: printf("neuf"); } } Dans cette fonction tous les break ont t oublis. Par consquent, lappel print_chiffre(7); ee e e achera : septhuitneuf Ce qui nest peut-tre pas le rsultat escompt. e e e

I.2. Probl`mes de calcul sur les nombres rels e e

I.1.4

Passage des param`tres par adresse e

En langage C, les param`tres des fonctions sont toujours passs par valeur : il e e sont copis localement dans la fonction. Ainsi, une modication dun param`tre e e dans la fonction reste localise ` cette fonction, et la variable de lappelant nest e a pas modie. e Pour pouvoir modier une variable de la fonction appelante, il faut raliser e un passage par adresse explicite. Par exemple, une fonction qui permute deux nombres rels aura le prototype : e void swapf(float *x, float *y); Et pour permuter les deux nombres x et y, on crira : e swapf(&x, &y); Si on a oubli dinclure le prototype de la fonction swap() avant de lappeler, e le risque est grand doublier de passer les adresses des variables. Cest une erreur frquement commise avec la fonction scanf() et ses variantes. e

I.2

Probl`mes de calcul sur les nombres rels e e

Avant dattaquer un programme quelconque utilisant des nombres rels, il est e indispensable davoir pris conscience des probl`mes fondamentaux induits par la e reprsentation approche des nombres rels sur toute machine informatique [2]. e e e Dans de nombreux cas, la prise en compte de ces dicults se fait simplement, e mais il peut savrer ncessaire davoir recours ` des algorithmes relativement e e a lourds, dans le cas par exemple ou la prcision de la reprsentation des rels par e e e la machine nest pas susante [3].

I.2.1

Egalit de rels e e

Sauf coup de chance, lgalit parfaite ne peut tre obtenue dans le monde e e e rel, il faut donc toujours tester lgalit ` pr`s. Mais il faut faire attention de e e ea e choisir un qui soit en rapport avec les valeurs ` tester. a Nutilisez pas : double a, b; ... if(a == b) /* Faux */ Mais quelque-chose du genre : #include <math.h>

10

Chapitre I. Quelques pi`ges du langage C e

if(fabs(a - b) <= epsilon * fabs(a)) qui permet un choix de epsilon indpendant de lordre de grandeur des vae ` condition que epislon soit strictement positif). leurs ` comparer (A a

I.2.2

Probl`mes darrondis e

La biblioth`que standard C propose des fonctions pour convertir des nombres e rels en entiers. oor() arrondit ` lentier immdiatement infrieur, ceil() arrondit e a e e a ` lentier immdiatement suprieur. Ces fonctions comportent deux pi`ges : e e e elles retournent un type double. Il ne faut pas oublier de convertir explicitement leur valeur en type int lorsquil ny a pas de conversion implicite. dans le cas dun argument ngatif, elles ne retournent peut-tre pas la valeur e e attendue: floor(-2.5) == -3 et ceil(-2.5) == -2. La conversion automatique des types rels en entiers retourne quant ` elle e a lentier immdiatement infrieur en valeur absolue : (int)-2.3 == -2. e e Pour obtenir un arrondi ` lentier le plus proche on peut utiliser la macro a suivante : #define round(x) (int)((x)>0?(x)+0.5:(x)-0.5)

I.2.3

Absence de dclaration des fonctions retournant des doubles e

Le type double occupe sur la plupart des machines une taille plus importante quun int. Comme les fonctions dont le type nest pas dclar explicitement sont e e considres comme retournant un int, il y aura probl`me si la valeur retourne ee e e tait en ralit un double : les octets supplmentaires seront perdus. e e e e Cette remarque vaut pour deux types de fonctions : les fonctions syst`me retournant des doubles. Limmense majorit de ces e e fonctions appartiennent ` la biblioth`que mathmatique et sont dclares a e e e e dans le chier math.h. Une exception ` noter est la fonction strtod() dnie a e dans stdlib.h. les fonctions des programmes utilisateur. Normalement toutes les fonctions doivent tre dclares avant dtre utilises. Mais cette dclaration nest pas e e e e e e rendue obligatoire par le compilateur. Dans le cas de fonctions retournant un type plus grand quun int, cest indispensable. Utilisez des chiers dentte (.h) pour dclarer le type de toutes vos fonctions. e e

I.3. Style des dclarations de fonctions e

11

I.3

Style des dclarations de fonctions e

Lexistence de deux formes direntes pour la dclaration des param`tres des e e e fonctions est source de probl`mes diciles ` trouver. e a Style K&R En C ( classique ) (galement appel Kernigan et Ritchie ou K&R pour faire ( ) e e plus court), une fonction se dclare sous la forme [4] : e int fonction(a) int a; { /* corps de la fonction */ ... } Et la seule dclaration possible dune fonction avant son utilisation est celle e du type retourn sous la forme : e int fonction(); Dans ce cas, tous les param`tres formels de types entiers plus petits que long int e sont promus en long int et tous les param`tres formels de types rels plus petit e e que double sont promus en double Avant lappel dune fonction, les conversions suivantes sont eectues sur les param`tres rels 1 : e e e les types entiers (char, short, int) sont convertis en long int les types rels (oat) sont convertis en double e Style ANSI La norme ansi concernant le langage C a introduit une nouvelle forme de dclaration des fonctions [5] : e int fonction(int a) { /* corps de la fonction */ ... }
1. ici (( rel )) sapplique ` param`tre, en opposition ` (( formel )) et non ` (( type )) (en e a e a a oppostion ` ( entier ) a ( ))

12

Chapitre I. Quelques pi`ges du langage C e

Avec la possibilit de dclarer le prototype complet de la fonction sous la e e forme : int fonction(int a); Si on utilise ce type de dclaration, aucune promotion des param`tres nest e e eectue dans la fonction. De mme, si un prototype ansi de la fonction appara e e t avant son appel, les conversions de types eectues convertiront les param`tres e e rels vers les types dclars dans le prototype. e e e Mlange des styles e Si aucun prototype ansi dune fonction (de la forme int fonction(int a)) na t vu avant son utilisation, le compilateur peut (selon les options de compiee lation) eectuer automatiquement les conversions de type cites plus haut, alors e quune fonction dclare selon la convention ansi attend les param`tres avec le e e e type exact qui appara dans la dclaration. t e Si on mlange les prototypes ansi et les dclarations de fonctions sous forme e e K&R, il est tr`s facile de produire des programmes incorrects d`s que le type des e e param`tres est char, short ou oat. e

I.4

Variables non initialises e

Les variables dclares ` lintrieur des fonctions (( automatiques ) sont e e a e ( )) alloues sur la pile dexcution du langage et ne sont pas initialises. e e e Par contre les variables dclares statiques sont garanties initialises ` zro. e e e a e

I.5

Ordre dvaluation indni e e

Sauf exceptions, le C ne dnit pas lordre dvaluation des lments de mme e e ee e prcdence dans une expression. Pire que a, la norme ansi dit explicitement que e e c le rsultat dune instruction qui dpend de lordre dvaluation nest pas dni si e e e e cet ordre nest pas dni. e Ainsi, leet de linstruction suivante nest pas dni : a[i] = i++; voici un e autre exemple de code dont le comportement nest pas dni : e int i = 3; printf("%d\n", i++ * i++); Chaque compilateur peut donner nimporte quel rsultat, mme le plus inate e tendu dans ces cas. Ce genre de construction doit donc tre banni. e

I.6. Allocation dynamique de la mmoire e

13

Les parenth`ses ne permettent pas toujours de forcer un ordre dvaluation e e total. Dans ce cas, il faut avoir recours ` des variables temporaires. a Lexception la plus importante ` cette r`gle concerne les oprateurs logiques a e e && et ||. Non seulement lordre dvaluation est garanti, mais en plus lvaluation e e est arrte d`s que lon a rencontr un lment qui xe dnitivement la valeur ee e e ee e de lexpression : faux pour && ou vrai pour ||.

I.6

Allocation dynamique de la mmoire e

Un des mcanismes les plus riches du langage C est la possibilit dutiliser des e e pointeurs qui, combine avec les fonctions malloc() et free() ouvre les portes de e lallocation dynamique de la mmoire. e Mais en raison de la puissance dexpression du langage et du peu de vrications e ralises par le compilateur, de nombreuses erreurs sont possibles. e e

I.6.1

Rfrence ` une zone mmoire non alloue ee a e e

La valeur dun pointeur dsigne ladresse de la zone mmoire vers laquelle il e e pointe. Si cette adresse ne correspond pas ` une zone de mmoire utilisable par le a e programme en cours, une erreur (segmentation fault) se produit ` lexcution du a e programme. Mais, mme si ladresse est valide et ne produit pas derreur, il faut e sassurer que la valeur du pointeur correspond ` une zone alloue correctement a e (avec malloc(), ou sous forme statique par une dclaration de tableau) par le e programme. Lexemple le plus frquent consiste ` rfrencer le pointeur NULL, qui par e a ee construction ne pointe vers aucune adresse valable. Voici un autre exemple de code invalide : int *iptr; *iptr = 1234; printf("valeur : %d\n", *iptr); iptr nest pas initialis et laectation *iptr = 1234; ne linitialise pas mais e crit 1234 ` une adresse alatoire. e a e

I.6.2

Rfrence ` une zone mmoire libre ee a e ee

` A partir du moment o` une zone mmoire a t libre par free(), il est interdit u e ee ee dadresser son contenu. Si cela se produit, on ne peut pas prdire le comportement e du programme.

14

Chapitre I. Quelques pi`ges du langage C e

Cette erreur est frquente dans quelques cas courants. Le plus classique est la e libration des lments dune liste cha ee. Lexemple suivant nest PAS correct : e ee n typedef struct LISTE { int valeur; struct LISTE *suivant; } LISTE; void libliste(LISTE *l) { for (; l != NULL; l = l->suivant) { free(l); } /* for */ } En eet la boucle for excute l = l->suivant apr`s la libration de la zone e e e pointe par l. Or l->suivant rfrence le contenu de cette zone qui vient dtre e ee e libre. ee Une version correcte de libliste() est : void libliste(LISTE *l) { LISTE *suivant; for (; l != NULL; l = suivant) { suivant = l->next; free(l); } /* for */ }

I.6.3

Libration dune zone invalide e

Lappel de free() avec en argument un pointeur vers une zone non alloue, e parce que le pointeur est initialise vers une telle zone, (cf I.6.1) ou parce que la e zone a dj` t libre (cf I.6.2) est une erreur. eaee ee L` aussi le comportement du programme est indtermin. a e e

I.7. Cha nes de caract`res e

15

I.6.4

Fuites

On dit quil y a fuite de mmoire lorsquun bloc allou par malloc nest plus e e rfrenc par aucun pointeur, et quil ne peut donc plus tre libr. Par exemple, ee e e ee la fonction suivante, sense permuter le contenu de deux blocs mmoire, fuit : elle e e perd le pointeur sur la zone tampon utilise, sans la librer. e e void mempermute(void *p1, void *p2, size_t length) { void *tmp = malloc(length); memcpy(tmp, p1); memcpy(p1,p2); memcpy(p2,tmp); } En plus cette fonction ne teste pas le rsultat de malloc(). Si cette derni`re e e fonction retournait NULL, on aurait dabord une erreur de rfrence vers une ee zone invalide. Pour corriger cette fonction, il sut dajouter free(tmp); ` la n du code. a Mais dans des cas rels, garder la trace des blocs mmoire utiliss, pour pouvoir e e e les librer nest pas toujours aussi simple. e

I.7

Cha nes de caract`res e

Les cha nes de caract`res sont gres par lintermdiaire des pointeurs vers e ee e le type char. Une particularit syntaxique permet dinitialiser un pointeur vers e une cha constante en zone de mmoire statique. Toutes les erreurs lies ` ne e e a lallocation mmoire dynamique peuvent se produire plus quelques autres : e

I.7.1

Dbordement dune cha de caract`res e ne e

Cela se produit principalement avec les fonctions telles que gets(), strcpy() ou sprintf() qui ne connaissent pas la taille de la zone destination. Si les donnes ` e a crire dbordent de cette zone, le comportement du programme est indtermin. e e e e Ces trois fonctions sont ` viter au maximum. La pire de toutes est gets() car ae il ny a aucun moyen dempcher lutilisateur du programme de saisir une cha e ne plus longue que la zone alloue en entre de la fonction. e e Il existe 3 fonctions alternatives, ` utiliser ` la place : a a fgets() remplace gets()

16

Chapitre I. Quelques pi`ges du langage C e

strncpy() remplace strcpy() snprintf() remplace sprintf(). Malheureusement cette fonction nest pas disponible sur tous les syst`mes. Mais il existe un certain nombre dimplmentation e e ( domaine public ) de snprintf(). ( ) Exemple : Le programme suivant nest pas correct : char buf[20]; gets(buf); if (strcmp(buf, "quit") == 0) { exit(0); } Utilisez plutt : o char buf[20]; fgets(buf, sizeof(buf), stdin); if (strcmp(buf, "quit") == 0) { exit(0); }

I.7.2

Ecriture dans une cha en mmoire statique ne e

La plupart des compilateurs et des diteurs de liens modernes stockent les e cha nes de caract`res initialises lors de la compilation avec des constructions du e e genre : char *s = "ceci est une cha^ne constante\n";

dans une zone mmoire non-modiable. Cela signie que la fonction suivante e (par exemple) provoquera une erreur ` lexcution sur certaines machines : a e s[0] = toupper(s[0]); Lutilisation du mot-cl const permet de dtecter cette erreur ` la compilation : e e a const char *s = "ceci est une cha^ne constante\n";

I.8. Pointeurs et tableaux

17

I.8

Pointeurs et tableaux

Une autre puissance dexpression du langage C provient de la possibilit dase similer pointeurs et tableaux dans certains cas, notamment lors du passage des param`tres aux fonctions. e Mais il arrive que cette facilit provoque des erreurs. e

I.8.1

Assimilation dun pointeur et dun tableau statique

Il arrive mme aux programmeurs expriments doublier que lquivalence e e e e entre pointeurs et tableaux nest pas universelle. Par exemple, il y a une dirence importante entre les deux dclarations suie e vantes : char tableau[] = "ceci est une chaine"; char *pointeur = "ceci est une chaine"; Dans le premier cas, on alloue un seul objet, un tableau de 20 caract`res et le e symbole tableau dsigne directement le premier caract`re. e e Dans le second cas, une variable de type pointeur nomme pointeur est ale loue dabord, puis une cha constante de 20 caract`res et ladresse de cette e ne e cha est stocke dans la variable pointeur. ne e

I.8.2

Appel de free() sur un tableau

Un tableau est une zone mmoire alloue soit statiquement ` la compilation e e a pour les variables globales, soit automatiquement sur la pile pour les variables locales des fonctions. Comme lacc`s ` ses lments se fait de mani`re qui ressemble e a ee e beaucoup ` lacc`s aux lments dune zone de mmoire alloue dynamiquement a e ee e e avec malloc(), on peut les confondre au moment de rendre la mmoire au syst`me e e et appeler par erreur free() avec un tableau en param`tre. e Si les prototypes de free() et malloc() sont bien inclus dans la porte de la e fonction en cours, cette erreur doit au minimum provoquer un warning ` la coma pilation.

I.9

Entres/sorties standard e

La biblioth`que de gestion des entres et sorties standard du langage C a t e e ee conue en mme temps que les premi`res versions du langage. Depuis la ncessit c e e e e de conserver la compatibilit avec les premi`res versions de cette biblioth`que ont e e e laiss subsister un certain nombre de sources derreur potentielles. e

18

Chapitre I. Quelques pi`ges du langage C e

I.9.1

Contrle des param`tres de printf et scanf o e

Les fonctions printf() et scanf() ainsi que leurs drives (fprintf(), fscanf(), e e sprintf(), sscanf(), etc.) acceptent un nombre variable de param`tres de types e dirents. Cest la cha de format qui indique lors de lexcution le nombre et le e ne e type exact des param`tres. Le compilateur ne peut donc pas faire de vrications. e e Ainsi, ces fonctions auront un comportement non prvisible si : e le nombre de param`tres pass est infrieur au nombre de spcications de e e e e conversion (introduites par %) dans la cha de format, ne le type dun param`tre ne correspond pas au type indiqu par la spcication e e e de conversion correspondante, la taille dun param`tre est infrieure ` la taille attendue par la spcication e e a e de conversion correspondante. Certains compilateurs (dont gcc) appliquent un traitement particulier ` ces a fonctions et vrient le type des param`tres lorsque le format est une cha e e ne constante qui peut tre analyse ` la compilation. e e a Rappelons les lments les plus frquemment rencontrs : ee e e les param`tres de scanf() doivent tre les adresses des variables ` lire, pas e e a les variables elles-mmes. Il faut crire : e e scanf("%d", &n); et non : scanf("%d", n); pour lire un double avec scanf(), il faut utiliser la spcication de format e %lf, par contre pour lacher avec printf() %f sut. ` Lexplication de cette subtilit se trouve ` la section I.3. A vous de la e a trouver.

I.9.2

Lecture de cha nes de caract`res e

La lecture et lanalyse de texte formant des cha nes de caract`res est un e probl`me souvent mal rsolu. Le cadre thorique gnral pour raliser cela correce e e e e e tement est celui de lanalyse lexicographique et syntaxique du texte, et des outils existent pour produire automatiquement les fonctions ralisant ces analyses. e Nanmoins, dans beaucoup de cas on peut se contenter de solutions plus e simples en utilisant les fonctions scanf(), fgets() et getchar(). Malheureusement ces fonctions prsentent quelques subtilits qui rendent leur e e usage problmatique. e scanf("%s", s); lit un mot de lentre standard, spar par des espaces, e e e

I.10. Processeurs 64 bits

19

tabulations ou retour ` la ligne. Cette fonction saute les sparateurs trouvs a e e a ` la position courante jusqu` trouver un mot et sarrte sur le premier a e sparateur trouv apr`s le mot. En particulier si le sparateur est un retour e e e e a ` la ligne, il reste dans le tampon dentre. e gets(s) lit une ligne compl`te, y compris le retour ` la ligne nal. e a c = getchar(); et scanf("%c", &c); lisent les caract`res un ` un. La e a seul dirence entre les deux est leur mani`re de retourner les erreurs en n e e de chier. Le mlange de ces trois fonctions peut produire des rsultats inattendus. En e e particulier appel ` getchar() ou gets() apr`s a e scanf("%s", s); retourneront toujours comme premier caract`re le sparateur qui a termin le mot e e e lu par scanf(). Si ce sparateur est un retour chariot, gets() retournera une ligne e vide. Pour lire des textes comportant des blancs et des retours ` la ligne, utilisez a exclusivement fgets() ou getchar(). Lutilisation de scanf() avec le format %s est ` rserver ` la lecture de a e a chiers structurs simples comportant des mots-cls spars par des espaces, des e e e e tabulations ou des retours ` la ligne. a

I.9.3

Lecture de donnes binaires e

Les fonctions fread() et fwrite() de la biblioth`que des entres/sorties standard e e permettent de lire et dcrire des donnes binaires directement, sans les coder en e e caract`res achables. e Les chiers de donnes produits ainsi sont plus compacts et plus rapides ` e a lire, mais les risques derreur sont importants. Le rdacteur et le lecteur doivent tre absolument daccord sur la reprsentation e e e des types de donnes de base ainsi crites. e e Il est fortement conseill de prvoir une signature du chier permettant de e e vrier quil respecte bien le format attendu par lapplication qui va le lire. e

I.10

Processeurs 64 bits

De plus en plus de processeurs ont une architecture 64 bits. Cela pose de nombreux probl`mes aux utilisateurs du langage C. Beaucoup de programmes e ne se compilent plus ou pire, se compile mais ne sexcutent pas correctement e

20

Chapitre I. Quelques pi`ges du langage C e

lorsquils sont ports sur une machine pour laquelle les pointeurs sont plus grands e quun int. La liste des cas ou lquivalence entiers/pointeurs est utilise implicitement e e est malheureusement trop longue et trop complexe pour tre cite enti`rement. e e e On ne verra que deux exemples parmi les plus frquents. e

I.10.1

Absence de dclarations des fonctions e

De mme que pour le type double, ` partir du moment o` les pointeurs nont e a u plus la taille dun entier, toutes les fonctions passant des pointeurs en param`tre e ou retournant des pointeurs doivent tre dclares explicitement (selon la norme e e e ansi) avant dtre utilises. e e Les programmes qui staient contents de dclarer les fonctions utilisant des e e e double rencontreront des probl`mes srieux. e e

I.10.2

Manipulation de pointeurs

Il arrive assez frquemment que des programmes utilisent le type int ou une signed int pour stocker des pointeurs avant de les raecter ` des pointeurs, ou e a rciproquement quils stockent des entiers dans un type pointeur et cela sans avoir e recours ` une union. a Dans le cas ou les deux types nont pas la mme taille, on va perdre une partie e de la valeur en le transformant en entier, avec tous les probl`mes imaginables e lorsquil sagira de lui rendre son statut de pointeur.

I.11

Pr-processeur e

Le pr-processeur du langage C (cpp) pose lui aussi certains probl`mes et peut e e tre a lorigine de certaines erreurs. e ` certaines erreurs de compilation inexplicables proviennent de la re-dnition e par le pr-processeur dun symbole de votre programme. Nutilisez jamais e didenticateurs risquant dtre utiliss aussi par un chier den-tte syst`me e e e e dans vos programmes. En particulier, tous les identicateurs commenant c par le caract`re ( soulign )) ( ) sont rservs au syst`me. e ( e e e e Lors de lcriture des macros, attention au nombre dvaluation des pae e ram`tres : puisquil sagit de macros et non de fonctions, les param`tres e e

I.11. Pr-processeur e

21

sont valus autant de fois quils apparaissent dans le corps de la macro, et e e non une seule fois au moment de lappel. Ainsi: #define abs(x) ((x)<0?-(x):(x)) value son argument deux fois. Donc abs(i++) incrmentera i deux fois. e e Comme dans lexemple prcdent, utilisez toujours des parenth`ses autour e e e des param`tres dans lexpansion de la macro. Cest le seul moyen de garantir e que les dirents oprateurs seront valus dans lordre attendu. e e e e

Chapitre II Un peu dalgorithmique

Le but de cette section est donner quelques pistes pour lutilisation des algorithmes que vous aurez appris par ailleurs, par exemple dans [6].

II.1

Introduction

Voici en introduction, quelques r`gles donnes par R. Pike dans un article sur e e la programmation en C [7]. La plupart des programmes sont trop compliqus, cest-`-dire plus compliqus e a e que ncessaire pour rsoudre ecacement le probl`me qui leur est pos. Poure e e e quoi? Essentiellement parce quils sont mal conus, mais ce nest pas le but de ce c document de discuter de conception, le sujet est trop vaste. Mais limplmentation des programmes est galement trop souvent complique e e e inutilement. L`, les quelques r`gles suivantes peuvent aider ` amliorer les choses. a e a e R`gle 1 e On ne peut prdire o` un programme va passer son temps. Les goulets e u dtranglement se retrouvent ` des endroits surprenants. Nessayez pas e a damliorer le code au hasard sans avoir dtermin exactement o` est e e e u le goulet. Mesurez. Nessayez pas doptimiser un programme sans avoir fait des mesures srieuses de ses performances. Et refaites-les rguli`rement. Si e e e un algorithme plus sophistiqu napporte rien, revenez ` plus simple. e a 22

R`gle 2 e

II.2. Allocation dynamique de la mmoire e

23

R`gle 3 e

R`gle 4 e

R`gle 5 e

R`gle 6 e

Les algorithmes sophistiqus sont lents quand n est petit, et en gnral e e e n est petit. Tant que vous ntes pas srs que n sera vraiment grand, e u nessayez pas dtre intelligents. (Et mme si n est grand, appliquez e e dabord la r`gle 2). e Les algorithmes sophistiqus sont plus bugus que les algorithmes e e simples, parce quils sont plus durs ` implmenter. Utilisez des ala e gorithmes et des structures de donnes simples. e Les structures de donnes suivantes permettent de traiter tous les e probl`mes : e tableaux, listes cha ees, n tables de hachage, arbres binaires. Bien sr, il peut tre ncessaire de les combiner. u e e Les donnes dominent. Si vous avez choisi les bonnes structures de e donnes, les algorithmes deviennent presque vidents. Les structures e e de donnes sont bien plus fondamentales que les algorithmes qui les e utilisent. Ne rinventez pas la roue. e Il existe des biblioth`ques de code disponibles librement sur le rseau e e Internet pour rsoudre la plupart des probl`mes algorithmiques clase e siques. Utilisez-les !. Il est presque toujours plus coteux de refaire quelque chose qui existe u dj`, plutt que daller le rcuprer et de ladapter. ea o e e

II.2

Allocation dynamique de la mmoire e

En plus des pi`ges cits au paragraphe I.6, on peut observer les r`gles suie e e vantes : Evitez les allocations dynamiques dans les traitements critiques. Lchec de e malloc() est tr`s dicile ` traiter. e a Tenez compte du cot dune allocation : malloc() utilise lappel syst`me sbrk() u e pour rclamer de la mmoire virtuelle au syst`me. Un appel syst`me est tr`s long e e e e e a e ` excuter. Allouez dynamiquement les objets dont la taille nest pas connue davance et peut varier beaucoup. Il est toujours dsagrable dimposer une taille maximum e e a un objet parce que le programmeur a prfr utiliser un tableau de taille xe. eee

24

Chapitre II. Un peu dalgorithmique

Librez au plus tt les objets non utiliss. e o e Limitez les copies dobjets allous dynamiquement. Utilisez les pointeurs. e

II.3

Pointeurs

Les pointeurs sont des outils puissants, mme si mal utiliss il peuvent faire e e e e e a de gros dgts, crivait Rob Pike dans [7] apr`s stre plant un ciseau ` bois e a e dans le pouce... Les pointeurs permettent des notations simples pour dsigner les objets. Considrons e e les deux expressions : nodep node[i] La premi`re est un pointeur vers un nud, la seconde dsigne un nud (le e e mme peut-tre) dans un tableau. Les deux formes dsignent donc la mme chose, e e e e mais la premi`re est plus simple. Pour comprendre la seconde, il faut valuer une e e expression, alors que la premi`re dsigne directement un objet. e e Ainsi lusage des pointeurs permet souvent dcrire de mani`re plus simple e e lacc`s aux lments dune structure complexe. Cela devient vident si lon veut e ee e accder ` un lment de notre nud : e a ee nodep->type node[i].type

II.4

Listes

Utilisez de prfrence les listes simplement cha ees. Elles sont plus faciles ` ee n a programmer (donc moins de risque derreur) et permettent de faire presque tout ce que lon peut faire avec des listes doublement cha ees. n Le formalisme du langage LISP est un tr`s bon mod`le pour lexpression des e e oprations sur les listes. e Dnissez ou utilisez un formalisme gnrique pour les listes dune application. e e e

II.5

Ensembles

Les ensembles de taille arbitrairement grande sont un peu diciles ` implmenter a e de mani`re ecace. Par contre, lorsquon a aaire ` des ensembles de taille raie a sonnable (moins dune centaine dlments) et connue davance, il est facile de les ee

II.6. Tris et recherches

25

implmenter de mani`re plutt ecace : llment n de lensemble est reprsent e e o ee e e par le bit n (mod 32) de llment n/32 dun tableau dentiers. ee Les oprations lmentaires sur ce type densemble se codent de mani`re trie ee e viale ` laide des oprateurs binaires &, |, ~. a e

II.6

Tris et recherches

Nessayez pas de programmer un tri. Il existe des algorithmes performants dans la biblioth`que standard C (qsort()). Ou bien utilisez les algorithmes de e Knuth [8]. Il en est de mme pour les probl`mes de recherche de donnes dans un ene e e semble. Voici un petit ventail des possibilits : e e recherche linaire : lalgorithme le plus simple. les lments nont pas besoin e ee dtre tris. La complexit dune recherche est en O(n), si n est le e e e nombre dlments dans la liste. Lajout dun lment se fait en temps ee ee constant. Cela reste la structure adapte pour tous les cas o` le temps e u de recherche nest pas le principal crit`re. Cette mthode est propose e e e par la fonction lsearch() de la biblioth`que standard C. e arbres binaires : les donnes sont tries et la recherche se fait par dichotomie. e e Les oprations de recherche et dajout se font en O(log(n)). Il existe e de nombreuses variantes de ce type dalgorithmes, en particulier une version prte ` lemploi fait partie de la biblioth`que C standard : e a e bsearch(). tables de h-coding : une fonction de codage (appele fonction de hachage) ase socie une cl numrique ` chaque lment de lensemble des donnes e e a ee e (ou ` un sous-ensemble signicativement moins nombreux). Si la fonca tion de hachage est bien choisie, les ajouts et les recherches se font en temps constant. En pratique, la cl de hachage nest jamais unique et e ne sert qu` restreindre le domaine de recherche. Une seconde tape a e faisant appel ` une recherche linaire ou ` base darbre est ncessaire. a e a e Certaines versions de la biblioth`que standard C proposent la fonction e hsearch().

II.7

Cha nes de caract`res e

Les cha nes de caract`res donnent lieu ` de nombreux traitements et posent e a pas mal de probl`mes algorithmiques. Voici quelques conseils pour une utilisation e

26

Chapitre II. Un peu dalgorithmique

saine des cha nes de caract`res : e vitez le limiter arbitrairement la longueur des cha : prvoyez lallocation e nes e dynamique de la mmoire en fonction de la longueur. e si vous devez limiter la longueur dun cha vriez quil ny a pas dbordement ne, e e et prvoyez un traitement de lerreur. e utilisez de prfrence les fonctions de lecture caract`re par caract`re pour ee e e les cha nes. Elle permettent les meilleures reprises en cas derreur. prvoyez ` lavance linternationalisation de votre programme : au minimum, e a considrez que lensemble des caract`res ` traiter est celui du codage ISO e e a Latin-1. utilisez les outils lex et yacc pour les traitements lexicographiques et syntaxiques un peu complexes : vos programmes gagneront en robustesse et en ecacit. e

Chapitre III Crer des programmes srs e u

Bien souvent un programmeur se satisfait dun programme qui a lair de fonctionner correctement parce que, apparemment, il donne un rsultat correct sur e quelques donnes de test en entre. Que des donnes compl`tement errones en e e e e e entre produisent des comportements anormaux du programme ne choque pas e outre-mesure. Certaines catgories de programmes ne peuvent pas se contenter de ce nie veau (peu lev) de robustesse. Le cas le plus frquent est celui de programmes e e e orant des services ` un grand nombre dutilisateurs potentiels, sur le rseau Ina e ternet par exemple, auxquels on ne peut pas faire conance pour soumettre des donnes senses en entre. Cela est particuli`rement crucial pour les programmes e e e e sexcutant avec des privil`ges particuliers (par exemple excuts sous lidentit e e e e e du super-utilisateur sur une machine Unix). En eet, les bugs causs par les dbordements de tableaux ou les autres cas e e dcrasement de donnes involontaires peuvent tre utiliss pour faire excuter ` e e e e e a un programme du code autre que celui prvu par le programmeur. Lorsque ce e code est le fruit du hasard, (des donnes brusquement interprtes comme du e ee code), lexcution ne vas pas tr`s loin et se termine gnralement par une erreur e e e e de type ( bus error ) ou ( segmentation violation ) ( ) ( ). Par contre, un programmeur mal intentionn peut utiliser ces dfauts en e e construisant des jeux de donnes dentre qui font que le code excut accidentele e e e lement ne sera plus rellement le fruit du hasard, mais bel et bien un morceaux de e 27

28

Chapitre III. Crer des programmes srs e u

programme prpar intentionnellement et destin en gnral ` nuire au syst`me e e e e e a e ainsi attaqu [9]. e Par consquent, les programmes ouverts ` lutilisation par le plus grand nombre e a doivent tre extrmement vigilants avec toutes les donnes quils manipulent. e e e De plus, comme il est toujours plus facile de respecter les r`gles en les applie quant d`s le dbut, on gagnera toujours ` prendre en compte cet aspect scurit e e a e e dans tous les programmes, mme si initialement ils ne semblents pas promis ` e a une utilisation sensible du point de vue scurit. e e Garnkel et Spaord ont consacr le chapitre 22 de leur livre sur la scurit e e e Unix et internet [10] ` lcriture de programme srs. Leurs recommandations sont a e u souvent reprises par dautres auteurs. La robustusse supplmentaire acquise par un programme qui respecte les e r`gles nonces ici sera toujours un bnce pour lapplication nale, mme si e e e e e e les aspects scurit ne faisaient pas partie du cahier des charges initiales. Un proe e gramme conu pour la scurit est en gnral aussi plus robuste face aux erreurs c e e e e communes, dpourvues darri`res penses malveillantes. e e e

III.1

Comment exploiter les bugs dun programme

Un expos exhaustif des techniques utilises par les (( pirates )) informatiques e e pour exploiter les bugs ou les erreurs de conception dun logiciel dpasse largee ment le cadre de ce document. Nous allons simplement prsenter ici un exemple e classique de bug qui tait prsent dans des dizaines (voire des centaines) de proe e grammes avant que lon ne dcouvre la mani`re de lexploiter pour faire excuter e e e un code arbitraire au programme qui le contient. Voici une fonction dun programme qui recopie la cha de caract`res quelle ne e reoit en argument dans un buer local (qui est situ sur la pile dexcution du c e e programme). int maFonction(char *in) { char buf[80]; strcpy(buf, in); ... return 0; }

III.1. Comment exploiter les bugs dun programme

29

Fig. III.1 Organisation des donnes sur la pile lors dans maFonction. e

Lors de lexcution de cette fonction, lorganisation des donnes sur la pile e e sera celle dcrite sur la gure III.1. e Sur cette gure, il appara clairement quun dbordement par le haut du t e tableau buf va craser sur la pile ladresse de retour de la fonction. Dans le e cas dune erreur involontaire, cela conduira ` un saut ` une adresse invalide et a a provoquera donc une erreur du type segmentation violation. Par contre, on peut exploiter cette lacune pour faire excuter au programme e en question un morceau de code arbitraire. Il sut pour cela de sarranger pour que les quatre premiers octets du dbordement soient une adresse donne sur la e e pile, dans la zone dja alloue, et que le reste du dbordement soit un programme e e e en code machine de la bonne longueur pour commencer pile ` ladresse que lon a a mise dans ladresse de retour. Ainsi, ` la n de lexcution de maFonction, le processeur va dpiler une a e e mauvaise adresse de retour et continuer son excution dans le code pass en exc`s e e e dans le tableau in. Ainsi expose, cette technique semble assez rudimentaire et dicile ` mettre en e a uvre. Il est cependant courant de trouver sur Internet dans des forums spcialiss e e des scripts tout faits capabables dexploiter ce type de vulnrabilit dans les e e applications les plus courantes des syst`mes existants. e

%&

'())

()

0'12

))

345

()

A B8  76

A96 @ 87         

"  ! $ #

 

30

Chapitre III. Crer des programmes srs e u

III.2

R`gles pour une programmation sre e u

La liste des r`gles qui suivent nest pas imprative. Des programmes peuvent e e tre srs sans respecter ces r`gles. Elle nest pas non plus susante : dune part e u e parce quil est impossible de faire une liste exhaustive (on dcouvre chaque see maine de nouvelles mani`res dexploiter des programmes apparement innocents), e et dautre part parce que seule une conception rigoureuse permet de protger un e programme contre les erreurs volontaires ou non des utilisateurs.

III.2.1

Eviter les dbordements e

Cest la r`gle principale. Il ne faut jamais laisser la possibilit ` une fonction e ea dcrire des donnes en dehors de la zone mmoire qui lui est destine. Cela peu e e e e para trivial, mais cest cependant des probl`mes de ce type qui sont utiliss tre e e dans la grande majorit des probl`mes de scurit connus sur Internet. e e e e Il y a en gros deux techniques pour arriver ` cela. Je ne prendrai pas partie a pour une technique ou une autre, par contre il est relativement vident que lon e ne peut pas (pour une fois) les mlanger avec succ`s. e e Allouer dynamiquement toutes les donnes. En nimposant aucune e limite statique ` la taille des donnes, le programme sadapte ` la taille relle a e a e des donnes et peut toujours les traiter sans risque derreur, ` condition que e a la machine dispose de susamment de mmoire. e Cest dailleurs l` que rside la dicult majeure de cette mthode. Lorsque a e e e la mmoire vient ` manquer, il est souvent tr`s dlicat de rcuprer lere a e e e e reur proprement pour mettre un diagnostic clair, librer la mmoire dj` e e e ea alloue mais inutilisable et retourner dans un tat stable pour continuer ` e e a fonctionner. Une autre dicult provient de la dicult dans certains cas de prdire la e e e taille dune donne. On se trouve alors contraint de rallouer plusieurs fois e e la zone mmoire o` elle est stocke, en provoquant autant de recopies de e u e ces donnes, ce qui ralenti lexcution du programme. e e Travailler uniquement avec des donnes de taille xe alloues e e statiquement. Avec cette technique on sinterdit tout recours ` la fonca tion malloc() ou ` ses quivalents. Toutes les donnes extrieures sont soit a e e e tronques pour contenir dans les buers de lapplication soit traites squentiellement e e e par morceaux susamment petits. Dans ce cas le traitement des erreurs est plus simple, par contre certains algorithmes deviennent complexes. Par exemple, comment raliser par exemple un tri de donnes arbitrairement e e grandes sans allocation dynamique de mmoire? e

III.2. R`gles pour une programmation sre e u

31

Il faut remarquer ici que les syst`mes de mmoire virtuelle aident ` gommer e e a les dfauts respectifs des deux approches. La possibilit dallouer des quantits e e e de mmoire bien suprieures ` la mmoire physique disponible aide ` retarder e e a e a lapparition du manque de mmoire dans le premier cas. La facult de la mmoire e e e virtuelle ` ne rclamer de la mmoire physique que pour les donnes rellement a e e e e rfrences permet dans la seconde approche de prvoir des tailles de donnes ee e e e statiques relativement grandes sans monopoliser trop de ressources si les donnes e relles sont tr`s souvent beaucoup plus petites. e e

III.2.2

Se mer des donnes e e

Si vous considrez que lutilisateur de votre programme veut nuire ` votre e a syst`me, toutes les donnes quil fournit en entre sont potentiellement dangee e e reuses. Votre programme doit donc analyser nement ses entres pour rejeter e intelligemment les donnes suspectes, sans pnaliser outre mesure les utilisateurs e e honntes. e Le premier point ` vrier a dj` t voqu : il faut viter que la taille des a e eaeee e e donnes dentre ne provoque un dbordement interne de la mmoire. Mais il y e e e e a dautres points ` vrier : a e Vrier les noms des chiers. En eet lutilisateur peut essayer dutiliser les e privil`ges potentiels de votre programme pour craser ou eacer des chiers e e syst`me. e Vrier la syntaxe des commandes. Chaque fois quun programme come mande lexcutuion dun script, il est possible dexploiter la syntaxe partie culi`rement riche du shell Unix pour faire faire ` une commande autre chose e a que ce pourquoi elle est conue. Par exemple si un programme excute le c e code suivant pour renommer un chier : sprintf(cmd, "mv %s %s.bak", fichier, fichier); system(cmd); pour renommer un chier, si fichier contient la valeur : toto toto.bak ; cat /etc/passwd ; la fonction system() va excuter : e mv toto toto.bak ; cat /etc/passwd ; toto toto.bak ; cat /etc/passwd; Ce qui va acher le chier des mots de passe crypts du syst`me en plus e e du rsultat initialement attendu. e Vrier lidentit de lutilisateur. Dans tous les cas o` cela est possible, e e u lidentication des utilisateurs ne limite pas directement ce quil peuvent faire, mais aide ` mettre en place des mcanismes de contrle dacc`s. a e o e

32

Chapitre III. Crer des programmes srs e u

III.2.3

Traiter toutes les erreurs

Eviter que des erreurs se produisent nest pas toujours possible. Prvoyez des traces des probl`mes de scurit, non visibles directement par e e e e lutilisateur. Par contre il est indispensable de prvenir lutilisateur de lexistence e et de la nature de ces traces (loi Informatique et liberts + eet dissuasif) e

III.2.4

Limiter les fonctionnalits e

Certaines fonctionnalits dun programme peuvent tre dangereuses. Il faut y e e songer d`s la spcication pour viter de fournir au pirate les moyens de parvenir e e e facilement ` ses ns. a possibilit de crer un shell e e achage de trop dinformation traitements sans limites

III.2.5

Se mer des biblioth`ques e e

Les r`gles ci-dessus devraient tre respectes par les programmeurs qui ont e e e raliser les biblioth`ques de fonctions utilises par votre application (biblioth`que e e e e C standard, interface graphique, calcul matriciel,...). Mais en tes-vous certains? e Lexprience montre que des probl`mes du style de ceux voqus ici sont prsents e e e e e dans de nombreux logiciels commerciaux, comme dans les logiciels libres. En gnral il nest pas possible dauditer tout le code des biblioth`ques utie e e lises, soit parce que celui-ci nest pas disponible, soit simplement par manque de e temps et/ou de comptence. e Interrogez-vous sur le type dalgorithme utilis par les fonctions appeles par e e votre code. Si lun deux prsente des risques de dbordement interne, vriez e e e deux fois les donnes, ` lentre et ` la sortie pour dtecter du mieux possible les e a e a e ventuelles tentatives dattaque. En cas de doute sur un rsultat votre programme e e doit le signaler au plus tt, et ne pas utiliser ce rsultat. o e

III.2.6

Bannir les fonctions dangereuses

Certaines fonctions de la biblioth`que C standard sont intrins`quement dangee e reuses parce que leur smantique ne permet pas de respecter les r`gles prsentes e e e e ci-dessus. Il faut donc sinterdire imprativement de les utiliser. Il peut y avoir e des cas o` ces fonctions peuvent tre utilises malgr tout de mani`re sre. A mon u e e e e u avis, mme dans ces cas, il faut les viter et leur prfrer une version sre. Cela e e ee u

III.3. Pour aller plus loin...

33

facilite la vrication a posteriori du code, en vitant de provoquer des fausses e e alarmes qui peuvent tre coteuses ` dsamorcer. De plus, le raisonnement qui e u a e vous a amen ` considr une utilisation dune fonction dangeureuse comme sre ea ee u peut tre faux ou incomplet et donc le risque nest pas limin compl`tement. e e e e Ne pas utiliser remplacer par remarque(s) gets() fgets() risque de dbordement e scanf() strtol(), strtod(), strtok(),... idem sprintf() snprintf() risque de dbordement e strcat() strncat() idem strcpy() strncpy() idem mktemp() mkstemp() section critique : entre la cration et louverture du e chier temporaire system() fork() & exec() possibilit dexploiter le e shell

III.3

Pour aller plus loin...

Le numro davril 1998 du magazine lectronique Sunworld Online propose e e une mthodologie de dveloppement de logiciels srs (SDSDM Software Dee e u velopment Security Design Methodology). Larticle est accessible ` ladresse: a http://www.sunworld.com/swol-04-1998/swol-04-security.html Adam Shostack, consultant en scurit informatique, a rdig un guide pour e e e e la relecture du code destin ` tourner dans un rewall: http://www.homeport. ea org/~adam/review.html qui est souvent cit comme rfrence pour lvaluation e ee e des logiciels de scurit. e e Le projet FreeBSD propose un ensemble de recommendations au dveloppeurs e qui souhaitent contribuer au projet : http://www.freebsd.org/security/programmers. html Matt Bishop a t lun des prcurseurs de la notion de programmation roee e buste. Ses articles sur le sujet font rfrence. http://olympus.cs.ucdavis.edu/ ee ~bishop/secprog.html Enn, le chapitre de [10] consacr ` la programmation sre est disponible en ea u ligne : ftp://ftp.auscert.org.au/pub/auscert/papers/secure_programming_ checklist

Chapitre IV Questions de style

Les r`gles prsentes ici ne sont pas impratives, il sagit juste dexemples de e e e e bonnes habitudes qui facilitent la relecture dun programme. Ce qui est le plus important, cest de penser quun programme doit pouvoir tre lu et compris par quelquun dextrieur, qui ne conna pas forcment tout e e t e du logiciel dont est extrait le morceau quil relit. La lisibilit dun code source e (qui peut sanalyser avec les r`gles de la typographie) est une tr`s bonne mesure e e de sa qualit. e Les guides de style pour les programmeurs C sont tr`s nombreux dans la e littrature. Presque chaque ouvrage sur le langage propose son style. Toutes les e grandes entreprises et les grands projets de logiciel ont leurs r`gles. e Un guide a servi de mod`le ` de nombreux programmeurs : le Indian Hill C e a Style and Coding Standards des Laboratoires Bells [11]. Ce guide a t amend ee e et modi de tr`s nombreuses fois, mais sert de rfrence implicite commune ` de e e ee a nombreux autres guides.

34

IV.1. Commentaires et documentation

35

IV.1
IV.1.1

Commentaires et documentation
Commentaires

Bien commenter un programme est sans doute la chose la plus dicile de toute la cha de dveloppement. Cest un des domaines o` ( le mieux est lennemi du ne e u ( bien ) sapplique avec le plus dvidence. ) e De mani`re gnrale, le commentaire permet dapporter au lecteur dun proe e e gramme une information que le programme lui-mme ne fournit pas assez clairee ment. Pour valuer la qualit dun commentaire, le recours aux r`gles de la typograe e e phie est prcieux : un commentaire ne doit pas tre surcharg de ponctuation ou e e e de dcorations. Plus il sera sobre, plus il sera lisible. e Un bon commentaire a surtout un rle introductif : il prsente ce qui suit, lalo e gorithme utilis ou les raisons dun choix de codage qui peut para surprenant. e tre Un commentaire qui paraphrase le code et vient apr`s coup napporte rien. e De mme, il vaut mieux un algorithme bien programm et bien prsent avec des e e e e noms de variables bien choisis pour aider ` sa comprhension, plutt quun code a e o brouillon tr`s compact suivi ou prcd de cent lignes dexplications. Lexemple e e e e extr`me du commentaire inutile est : e i++; /* ajoute 1 a la variable i */

Dailleurs, avec ce genre de commentaires, le risque de voir un jour le code et le commentaire se contredire augmente considrablement. e Enn, il est srement utile de rappeler quand crire les commentaires : tout u e de suite en crivant le programme. Prtendre repasser plus tard pour commenter e e un programme cest une promesse divrogne qui est tr`s dicile ` tenir. e a En-ttes de chiers e Il peut tre utile davoir en tte de chaque chier source un commentaire e e qui attribue le copyright du contenu ` son propritaire, ainsi quun cartouche a e indiquant le numro de version du chier, le nom de lauteur et la date de la e derni`re mise ` jour, avant une description rapide du contenu du chier. e a Exemple (ici len-tte est maintenue automatiquement par RCS) : e /*** *** Copyright (c) 1997,1998 CNRS-LAAS *** *** $Source: /home/matthieu/cvs/doc/cours/C/style.tex,v $ *** $Revision: 1.9 $

36

Chapitre IV. Questions de style

*** $Date: 1999/04/05 19:45:49 $ *** $Author: matthieu $ *** *** Fonctions de test sur les types du langage ***/ Remarque : la notice de copyright rdige ainsi na aucune valeur lgale en e e e France. Pour une protection ecace dun programme, il faut le dposer aupr`s e e dun organisme spcialis. Nanmoins, en cas de conit, la prsence de cette notice e e e e peut constituer un lment de preuve de lorigine du logiciel. ee En-ttes de fonctions e Avant chaque fonction, il est tr`s utile davoir un commentaire qui rappelle le e rle de la fonction et de ses arguments. Il est galement tr`s utile dindiquer les o e e direntes erreurs qui peuvent tre dtectes et retournes. e e e e e Exemple : /** ** insertAfter - ins`re un bloc dans la liste apr`s un bloc e e ** particulier ** ** param`tres: e ** list: la liste dans laquelle insrer le bloc. NULL cre une e e ** nouvelle liste ** pBloc: pointeur sur le bloc a insrer e ** ** retourne: la nouvelle liste **/ Donner le type des param`tres ne sert ` rien, car la dclaration formelle de la e a e fonction, avec le type exact suit immdiatement. e Commentaires dans le code On peut presque sen passer si lalgorithme est bien prsent (voir aussi ree e marque sur la complexit au chapitre II). e Il vaut mieux privilgier les commentaires qui rpondent ` la question poure e a quoi? par rapport ` ceux qui rpondent ` la question comment?. a e a Les commentaires courts peuvent tre placs en n de ligne. D`s quun come e e mentaire est un peu long, il vaut mieux faire un bloc avant le code comment. e

IV.2. Typologie des noms

37

Pour un bloc, utiliser une prsentation sobre du genre : e /* * Un commentaire bloc * Le texte est mis en page de mani`re simple et claire. e */ Les commentaires placs dans le code doivent tre indents comme le code e e e quils prc`dent. e e Nessayez pas de crer des cadres compliqus, justis ` droite ou avec une e e e a apparence 3D. Cela napporte aucune information, et est tr`s dur ` maintenir e a propre lorsquon modie le commentaire.

IV.1.2

Documentation

Maintenir une documentation ` part sur le fonctionnement interne dun proa gramme est une mission quasiment impossible. Cest une mthode ` viter. Il e a e vaut mille fois mieux intgrer la documentation au programme sous forme de e commentaires. Cette logique peut tre pousse un peu plus loin en utilisant dans les come e A mentaires les commandes dun logiciel de formattage de documents (tro, L TEX, etc.). Il sut alors davoir un outil qui extrait les commentaires du source et les formatte pour retrouver un document externe avec une prsentation plus riche e que des commentaires traditionnels. Knuth a formalis cette approche sous le e nom de programmation littraire [12] e

IV.2

Typologie des noms

La typologie des noms (choix des noms des variables, des fonctions, des chiers) est un lment primordial dans la lisibilit dun programme. Celle-ci doit ee e respecter plusieurs contraintes: cohrence choisissez une logique dans le choix des noms de variables et e gardez-l`. a signication choisissez des noms qui ont un sens en relation avec le rle o de la variable ou de la fonction que vous nommez. modularit indiquez lappartenance dun nom ` un module. e a non-ambiguit vitez ambigu es pour distinguer deux variables semblables ee t (variations sur la casse par exemple), utilisez des moyens simples (suxes

38

Chapitre IV. Questions de style

numriques). Attention, certains diteurs de liens imposent que les 6 (six !) e e premiers caract`res dun identicateur soient discriminants. e Il existe plusieurs conventions de choix des noms de variables et de fonctions dcrites dans la littrature. Parmi celles, ci on peut citer la ( notation hongroise ) e e ( ) prsente entre autres par C. Simonyi [13] qui code le type des objets dans leur e e nom. Sans entrer dans un mcanisme aussi systmatique, il est bon de suivre quelques e e r`gles : e les noms avec un underscore en tte ou en queue sont rservs au syst`me. e e e e Ils ne doivent donc pas tre utiliss par un utilisateur de base. e e mettre en majuscules les constantes et les noms de macros dnies par e #define. Les macros qui se comportent comme une fonction peuvent avoir un nom en minuscules. exemples : #define VITESSE_MAX (1.8) #define MAX(i,j) ((i) > (j) ? (i) : (j)) #define bcopy(src,dst,n) memcpy((dst),(src),(n)) MAX est identi comme une macro (et doit le rester). En eet cette macro e value deux fois lun de ses arguments. Ecrire max risquerait de le faire e oublier et de conduire ` des erreurs. a mettre en majuscules galement les noms de types dnis par typedef et les e e noms de structures. utiliser de prfrence le mme nom pour une structure et le type dnit ee e e pour elle. exemple : typedef struct POS { double x; double y; double theta; } POS; les constantes dans les enum commencent par une majuscule. les autres noms (variables, fonctions,... ) commencent par une minuscule et sont essentiellement en minuscules. Quand un nom comporte plusieurs mots, on peut utiliser une majuscule pour introduire chaque nouveau mot. viter les noms trop proches typographiquement. Par exemple les caract`res e e ((l) et ( sont diciles a distinguer, il en sera de mme des identicateurs ) (1)) ` e ( ) et ((ul)). (u1)

IV.3. Dclarations e

39

si une fonction retourne une valeur qui doit tre interprte comme valeur e ee boolenne dans un test, utiliser un nom signicatif du test. Par exemple e valeurCorrecte() plutt que testValeur(). o la longueur dun nom nest pas une vertu en soi. Un index de tableau na pas besoin dtre plus complexe que i. Les variables locales dune fonction e peuvent souvent avoir des noms tr`s courts. e les variables globales et les fonctions doivent au contraire avoir des noms qui comportent le maximum dinformation. Mais attention, des noms trop longs rendent la lecture dicile.

IV.3

Dclarations e

Utilisez le C ANSI, et incluez systmatiquement des prototypes des fonctions e que vous utilisez. Tous les compilateurs C ANSI ont une option pour produire un avertissement ou une erreur quand une fonction est appele sans que son e prototype nai t dclar. ee e e Bien entendu, dclarez un type ` toutes vos variables et ` toutes vos fonctions. e a a La dclaration implicite en entier est une source derreurs. e Pour dclarer des types compliqus, utilisez des typedefs. Cela rend le code e e plus lisible et plus modulaire.

IV.4

Indentation

Lindentation permet de mettre en valeur la structure de lalgorithme. Il est capital de respecter une indentation cohrente avec cette structure. Mais, comme e pour la typologie des noms de variables, il ny a pas de r`gles uniques. e Personnellement, jutilise un syst`me dindentation bien rsum par lexemple e e e suivant. Il a lavantage dune certaine compacit. e if (condition) { /* 1er cas */ x = 2; } else { /* 2nd cas */ x = 3; } Dautres prf`rent aligner les accolades ouvrantes et fermantes qui se corresee pondent sur une mme colonne : e if (condition)

40

Chapitre IV. Questions de style

{ /* 1er cas */ x = 2; } else { /* 2nd cas */ x = 3; } Lincrment de base de lindentation doit tre susant pour permettre de e e distinguer facilement les lments au mme niveau. Quatre caract`res semble une ee e e bonne valeur. Il existe plusieurs outils qui maintiennent lindentation dun programme automatiquement. Lditeur emacs propose un mode spcique pour le langage C e e qui indente les lignes tout seul au fur et a mesure de la frappe, selon des r`gles e programmables. Lutilitaire Unix indent permet de refaire lindentation de tout un chier. Un chier de conguration permet de dcrire son style dindentation favori. e

IV.5

Boucles

Evitez absolument de transformer votre code en plat de spaghetti. Le langage C permet de nombreuses constructions qui dtournent le cours normal de e lexcution du programme : break, continue, goto... e Toutes ces constructions doivent tre vites d`s quelles rendent dicile le e e e e suivi du droulement dun programme. Par la suite, sil faut prendre un compte e un nouveau cas, cela ne pourra se faire quen ajoutant des nuds dans le plat... Mais attention, dans un certain nombre de cas, notamment le traitement des erreurs, lutilisation judicieuse dun break ou dun goto est plus lisible quune imbrication profonde de tests.

IV.6

Expressions complexes

D-com-po-sez les expressions trop complexes en utilisant ventuellement des e e variables intermdiaires. Cela diminue le risque derreur lors de la saisie et auge mente la lisibilit pour la suite. e Pour dclarer un type complexe, utilisez plusieurs typedefs intermdiaires. e e

IV.7. Conversion de types

41

Par exemple, pour dclarer un tableau de dix pointeurs sur fonctions enti`res e e avec un param`tre entier, les deux typedefs suivants sont bien plus lisibles que ce e que lon obtiendrait en essayant de lcrire directement (laiss en exercice pour le e e lecteur). typedef int (*INTFUNC)(int); typedef INTFUNC TABFUNC[10];

IV.7

Conversion de types

Attention, terrain glissant. Normalement, il ne devrait pas y en avoir. Avant dutiliser un cast, demandez-vous toujours sil ny a pas un probl`me dans votre e programme qui vous oblige ` faire ce cast. a Les pommes ne sont pas des poires, cest vrai aussi des types informatiques. Si vraiment vous avez des types qui peuvent reprsenter plusieurs objets dirents, e e les unions sont peut-tre un peu plus lourdes ` manier, mais elles orent des e a possibilits de vrication au compilateur. e e En eet, le plus grand pi`ge tendu par les cast, est que vous obligez le compie lateur ` accepter ce que vous tapez, en lui tant tout droit ` la critique. Or il est a o a possible de faire des erreurs partout, y compris dans lutilisation des cast. Mais le compilateur na plus aucun moyen de les dtecter. e

IV.8

Assertions

Le mcanisme des assertions permet de dclarer des prdicats sur les variables e e e dune fonction qui doivent tre vrais (appels aussi invariants). En cas de sie e tuation anormale (en gnral ` la suite dune erreur de logique du programme) e e a lassertion fausse provoquera un arrt du programme. e Les assertions sont introduites par le chier den-tte assert.h et sont crites e e sous la forme : assert()(expression) Ce mcanisme simple permet daider ` la mise au point dalgorithmes un peu e a complexes, ` la fois parce quils guident le programmeur pendant le codage et a quils permettent daider ` dtecter les erreurs. a e

Rfrences bibliographiques ee
[1] S. Summit. C Programming FAQs: Frequently Asked Questions. Addison-Wesley, 1995. [2] D. Goldberg. What every computer scientist should know about oating-point arithmetic. ACM Computing Surveys, 23(1):548, March 1991. [3] D.E. Knuth. Seminumerical Algorithms, volume 2 of The Art of Computer Programming. Addison-Wesley, 1973. [4] B.W. Kernighan and D.M. Ritchie. The C Programming Language. Prentice-Hall, 1978. [5] B.W. Kernighan and D.M. Ritchie. The C Programming Language. Prentice-Hall, 2nd edition, 1988. [6] D.E. Knuth. Fundamental Algorithms, volume 1 of The Art of Computer Programming. Addison-Wesley, 1973. [7] R. Pike. Notes on Programming in C. [8] D.E. Knuth. Sorting and Searching, volume 3 of The Art of Computer Programming. Addison-Wesley, 1973. [9] Aleph One (aleph1@underground.org). Smashing the stack for fun and prot. Phrack, (49), November 1996. [10] S. Garnkel and G. Spaord. Practical Unix and Internet Security. OReilly and Associates, 2nd edition, 1996. [11] L.W. Cannon, R.A. Elliot, L.W. Kirchho, J.H. Miller, J.M. Milner, R.W. Mitze, E.P. Shan, and N.O. Whittington. Indian Hill C style and coding standards. Bell Labs. [12] D.E. Knuth. Literate programming. Computer Journal, 28(2):97 111, 1984. [13] C. Simonyi and M. Heller. The hungarian revolution. Byte, pages 131138, Aot 1991. u 42

Index
Symboles & . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 && . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 = ................................ 7 == . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 | . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 || . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 64 bits . . . . . . . . . . . . . . . . . . . . . . . . . . 19 A allocation mmoire . . . . . . . . . . . . . e ansi . . . . . . . . . . . . . . . . . . . . . . . . . . . . arrondi . . . . . . . . . . . . . . . . . . . . . . . . . assert . . . . . . . . . . . . . . . . . . . . . . . . . . . assert.h . . . . . . . . . . . . . . . . . . . . . . . assertions . . . . . . . . . . . . . . . . . . . . . . . 13 11 10 41 41 41 continue . . . . . . . . . . . . . . . . . . . . . . . . 40 cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 D dclarations . . . . . . . . . . . . . . . . . 11, e documentation . . . . . . . . . . . . . . . . . donnes e binaires . . . . . . . . . . . . . . . . . . . . . double . . . . . . . . . . . . . . . . . . . 10, 11, 39 37 19 20

E galit . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 e e emacs . . . . . . . . . . . . . . . . . . . . . . . . . . 40 en-tte . . . . . . . . . . . . . . . . . . . . . . . . . 35 e entres/sorties . . . . . . . . . . . . . . . . . . 17 e exec . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 F FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 fgets . . . . . . . . . . . . . . . . . 15, 18, 19, 33 oat . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 oor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 fork . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 fprintf . . . . . . . . . . . . . . . . . . . . . . . . . . 18 fread . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 free . . . . . . . . . . . . . . . . . . . . . 13, 14, 17 fscanf . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 fuites . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 fwrite . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 G getchar . . . . . . . . . . . . . . . . . . . . . . 18, 19 43

B boucles . . . . . . . . . . . . . . . . . . . . . . . . . 40 break . . . . . . . . . . . . . . . . . . . . . . . . . 8, 40 bsearch . . . . . . . . . . . . . . . . . . . . . . . . . 25 C calcul rel . . . . . . . . . . . . . . . . . . . . . . . 9 e caract`res e cha nes de . . . . . . . . . . . . . . . . . . 15 case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 ceil . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 char . . . . . . . . . . . . . . . . . . . . . . . . . 12, 15 commentaires . . . . . . . . . . . . . . . . . . . 35 const . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

44

INDEX

gets . . . . . . . . . . . . . . . . . . . . . 15, 19, 33 goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 H hsearch . . . . . . . . . . . . . . . . . . . . . . . . . 25 I indent . . . . . . . . . . . . . . . . . . . . . . . . . 40 indentation . . . . . . . . . . . . . . . . . . . . . 39 int . . . . . . . . . . . . . . . . . . . . . . . . . . 10, 20 K Kernigan et Ritchie . . . . . . . . . . . . . 11 L lex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 long int . . . . . . . . . . . . . . . . . . . . . . . . . 11 lsearch . . . . . . . . . . . . . . . . . . . . . . . . . . 25 M malloc . . . . . . . . . . . 13, 15, 17, 23, math.h . . . . . . . . . . . . . . . . . . . . . . . . . mkstemp . . . . . . . . . . . . . . . . . . . . . . . . mktemp . . . . . . . . . . . . . . . . . . . . . . . . . 30 10 33 33

sbrk . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 scanf . . . . . . . . . . . . . . . . . 9, 18, 19, 33 short . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 snprintf . . . . . . . . . . . . . . . . . . . . . 16, 33 sprintf . . . . . . . . . . . . . . . 15, 16, 18, 33 sscanf . . . . . . . . . . . . . . . . . . . . . . . . . . 18 stdlib.h . . . . . . . . . . . . . . . . . . . . . . . 10 strcat . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 strcpy . . . . . . . . . . . . . . . . . . . 15, 16, 33 strncat . . . . . . . . . . . . . . . . . . . . . . . . . . 33 strncpy . . . . . . . . . . . . . . . . . . . . . . 16, 33 strtod . . . . . . . . . . . . . . . . . . . . . . . 10, 33 strtok . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 strtol . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 switch . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 system . . . . . . . . . . . . . . . . . . . . . . 31, 33 T tableaux . . . . . . . . . . . . . . . . . . . . . 7, typedef . . . . . . . . . . . . . . . . . . . . . . 38, types conversion de . . . . . . . . . . . . . . . typologie . . . . . . . . . . . . . . . . . . . . . . . 17 39 41 37

N non-initialises e variables . . . . . . . . . . . . . . . . . . . . 12 O ordre dvaluation . . . . . . . . . . . . . . 12 e P passage par adresse . . . . . . . . . . . . . . 9 pointeurs . . . . . . . . . . . . . . . . . . . . . . . 17 prprocesseur . . . . . . . . . . . . . . . . . . . 20 e printf . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Q qsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 S

U union . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 unsigned int . . . . . . . . . . . . . . . . . . . . . 20 Usenet . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Y yacc . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Vous aimerez peut-être aussi