Vous êtes sur la page 1sur 27

243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Aide mémoire et notions de base du langage C

Voici l’aspect général d’un programme écrit en langage C

#include <stdio.h> // inclusion pour le compilateur des fichiers


#include <stdlib.h> // d’entête où les fonctions telle « printf() »
// sont déclarées

#define VALEUR 100// on déclare une constante (un alias) où le mot


// VALEUR est associé au nombre 100
/*-----------------------------------------------------------*/
/* fonction principale, celle qui est exécutée en premier */
/*-----------------------------------------------------------*/
void main(void){
printf("Bonjour tout le monde\n\n");
sommation1(VALEUR);
sommation2(100);
}
/*---------------------------------------------------------------------*/
/*-----------------------------------------------------------*/
/* cette fonction calcul la somme de N premiers nombres */
/* et affiche le résultat à l'écran via la fonction printf() */
/*-----------------------------------------------------------*/
void sommation1(unsigned int nombre){
unsigned int calcul; // on déclare une variable "calcul" qui est du type entier
// non-signé

calcul = 0; // on démarre la variable calcul à 0


while(nombre > 0){
calcul = calcul + nombre;
nombre = nombre -1;
}
printf("la somme1 donne : %d\n",calcul);
}

/*-----------------------------------------------------------*/
/* cette fonction calcul la somme de N premiers nombres */
/* à l'aide d'une équation et affiche le résultat à l'écran */
/* via la fonction printf() */
/*-----------------------------------------------------------*/
void sommation2(unsigned int nombre){
nombre = nombre*(nombre+1)/2;
printf("la somme2 donne : %d\n",nombre);
}

Nous allons faire l’analyse de ce petit programme ensemble en utilisant le programme « CodeBlocks »
déjà installé sur votre ordinateur. Vous pourrez si vous le désirez, en faire l’installation chez vous ce qui
vous donnera l’occasion de tester vos connaissance et aussi de travailler vos exercices.

André Touchette Page 1/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Informations générales sur la syntaxe du langage C


Comme le montre le petit programme précédent, la syntaxe du langage C est relativement simple mais
peu devenir plus complexe à lire lorsque l’on traite des notions comme les pointeurs. Pour le moment
nous allons explorer les mots réservés de base qui ne peuvent en aucun cas être employés comme
variable ou nom de fonction. Dans le tableau plus bas est dressée la liste de ces mots réservés.

Dans la plupart des langages, il y a toujours des éléments nous permettant d’effectuer des tests logiques
donnant ainsi la possibilité de prendre des décisions selon le résultat obtenu comme par exemple, est-ce
que le contenu de la variable « a » est plus grand que le contenu de la variable « b », si oui alors on
exécute certaines instructions sinon on en exécute d’autres. Aussi il est possible d’effectuer certaines
instructions plusieurs fois selon nos besoins, alors l’utilisation d’instructions de bouclage sa employée.
Ces instructions font partie des mots réservés et nous allons en explorer quelques uns.

Avant de faire l’analyse du programme du début, nous allons mettre en lumière quelques éléments de
base entourant la syntaxe du langage C. Je la ferai sous la forme d’une suite d’énoncés.

 Lorsque l’on veut mettre une ligne de commentaires dans le programme on place deux barres
obliques comme ceci // le texte qui suit est alors un commentaire ne faisant pas partie des
instructions du programme. Voir le programme en exemple.
 Lorsque l’on veut mettre plusieurs lignes en commentaires alors on place une barre oblique
suivie d’un astérisque /* on place ensuite à la fin de la ligne complétant le commentaire la
séquence inverse soit */.
 Une instruction se termine toujours par un point virgule « ; »
 La position horizontale d’une instruction dans un programme n’a aucune influence pour le
compilateur, l’indentation des instructions permet seulement au lecteur d’avoir une meilleure
compréhension visuelle de la structure et de l’enchaînement des instructions.
 Dans un test conditionnel, tel un « if » , un « else » les instructions qui seront exécutées doivent
être placées entre des accolades { instructions à être exécutées }
 De même pour une boucle « for », une boucle « while » ou les instructions contenues dans une
fonction.
 La déclaration de variables doit se faire au début d’une fonction juste avant les premières
instructions exécutables ceci vaut pour les variables locales à chaque fonction.
 La fonction « main() » est la première à être exécutée lorsque le compilateur aura terminé la
traduction de votre programme. Elle doit être présente et doit avoir obligatoirement ce nom.
Toutes les autres fonctions pourront avoir n’importe quel nom mais sans espace dans leur nom.
 Normalement le langage C est sensible à la casse soit aux majuscules et minuscules. Il est
fortement conseillé de mettre tout les termes employés en minuscules. Par convention on met
en majuscule que les éléments définis comme des constantes comme dans le programme plus
haut, où j’ai définie une constante « VALEUR » qui lui sera assignée le nombre 100. À chaque
fois que le compilateur va rencontrer le mot « VALEUR » il va substituer ce mot par le nombre
100.

André Touchette Page 2/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Il y a bien sûr d’autres éléments de la syntaxe que nous verrons au fur et à mesure que nous avancerons
dans la matière.

Mots réservés « Reserved keywords »


Les mots suivants sont réservés et ne doivent pas être utilisés comme identificateurs ou variables:

Mots réservé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

Certaines implémentations réservent aussi les mots fortran et asm.

Les spécificateurs de type lors de la déclaration de variables


Un spécificateur de type permet de qualifier entre autres une variable que l’on se déclare comme
étant d’un type donné. Ce type correspond à sa représentation en mémoire et l’espace quelle occupe.
Par exemple, si je déclare la variable suivante : unsigned int toto; alors la variable toto de type entier
occupera un espace mémoire de 32 bits non signé.

Spécificateurs de type
Indique qu’il n’y a pas de type. Utilisé devant la déclaration d’une
void fonction indiquant que celle-ci ne retourne rien ou quelle ne reçoit
aucun paramètre lors de son appel ex. : void fonction1(void)
Un seul octet, pouvant contenir un caractère du jeu de caractères de
char
la machine utilisée ou simplement un nombre entre 0 et 0xFF.
short Un entier court donc la moitié ou la même grandeur qu’un int
Reflète typiquement la taille naturelle des nombres entiers sur la
int
machine utilisée. Peut être de 16 bits sur le µC et 32 bits sur le PC
long Indique que l’élément associé à ce type sera représenté sur 32 bits
float Un nombre en virgule flottante en simple précision sur 32 bits
double Un nombre en virgule flottante en double précision sur 64 bits
signed Représente un nombre pouvant être négatif.
unsigned Spécifie que le type employé représente un nombre positif

André Touchette Page 3/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

On peut ajouter l’un des mots short ou long à int; mais le sens reste le même si l’on omet le int. On
peut ajouter l’un des mots signed et unsigned à int ou bien à char. Si l’on n’écrit que signed ou unsigned
cela représente un int. Le spécificateur signed devant un char sert à forcer les objets de ce type à porter
un signe; tandis que pour un int il est par défaut de type signed si il n’est pas précisé.

Les types de données et leurs tailles


Un spécificateur de type permet de qualifier entre autres une variable que l’on se déclare comme
étant d’un type donné. Ce type correspond à sa représentation en mémoire et l’espace quelle occupe.
Par exemple, si je déclare la variable suivante : unsigned int toto; alors la variable toto de type entier
occupera un espace mémoire de 32 bits non signé donc pourra prendre la valeur 0 à 4 294 967 295 soit
232

Les types de données et leurs tailles


signed char -128 à 127
unsigned char 0 à 255
int -2 147 483 648 à 2 147 483 647
unsigned int 0 à 4 294 967 295
float -3,4x1038 à 3,4x1038
double -1,7x10308 à 1,7x10308

Les séquences d’échappement « Backslash escapes »


Si vous souhaitez utiliser ces éléments, dites vous qu’ils ne forment pas deux caractères mais un seul
code en mémoire. Par exemple \r lorsque traduit en une valeur réelle en mémoire, correspond à 13 en
décimal ou à 0xd en hexadécimal. Donc dans l’instruction suivante, on retrouve l’utilisation de \r qui
correspond à un retour de chariot ou autrement dit, au retour du curseur au début de la ligne à gauche.
printf(‘’Allo tout le monde \r ’’); le \r sera traduit par le compilateur par le code ascii 0x0d au lieu de
vraiment imprimer une barre oblique suivie d’un r.

Séquences d’échappement

\\ Littéral backslash (donne un vrai \) \t Tabulation horizontale

\" Guillemet « Double quote » \v Tabulation verticale

\' Apostrophe « Single quote » \a Caractère d’alerte (sonnerie, bell)

\n Fin de ligne « Newline » (line feed) \f Saut de page « Form feed »

\r Retour de chariot « Carriage return » \b Retour en arrière « backspace »

\ooo Nombre octal \0 Caractère Null qui vaut 0

\xhh Nombre hexadécimal

André Touchette Page 4/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Les opérateurs arithmétiques


Les opérateurs arithmétiques binaires sont + - * / % soit donc l’addition, la soustraction, la
multiplication, la division et enfin le modulo.

Les opérateurs de comparaison


Opérateurs de comparaison

> Est-ce plus grand que < Est-ce plus petit que

>= Est-ce plus grand ou égal à <= Est-ce plus petit ou égal à

== Est-ce égal à != Est-ce non égal à

Les opérateurs logiques


Opérateurs logiques

&& a && b est-ce que a et b sont vrais || a || b est-ce que a ou b est vrai

Les expressions conditionnelles


Supposons le bout de programme suivant :

If (a > b){
y=a;
}
else{
y = b;
}
signifie que si la valeur de a est plus grande que la valeur de b, alors y = a sinon y = b. Ces instructions
pourraient être remplacées par une seule ligne plus compacte, la voici :

y = (a > b) ? a : b; correspond à expr1 ? expr2 : expr3 ce qui se lit est-ce que l’ expr1 est vrai
si oui alors prend comme résultat expr2 sinon prend expr3.

Les opérateurs de traitement bit à bit


Le C fournit six opérateurs qui réalisent des manipulations au niveau des bits qu’aux entiers seulement,
c’est-à-dire le char, short, int, long, signés ou non.

Opérateurs sur les bits

& ET bit à bit : ex. : 0x3a & 0x2f = 0x2a << Décalage à gauche ex. : 0x3a <<4 = 0xa0

| OU inclusif bit à bit ex. : 0x3a | 0x2f = 0x3f >> Décalage à droite ex. : 0x3a >>4 = 0x03

^ OU exclusif bit à bit ex. : 0x3a ^ 0x2f = 0x15 ~ Complément à 1 ex. : ~ 0x3a = 0xc5

André Touchette Page 5/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Les opérateurs et les opérations d’affectation


L’expression i = i+2, où la variable de gauche se répète immédiatement à droite, peut s’écrire sous la
forme compacte suivante : i += 2
L’opérateur += s’appelle un opérateur d’affectation. En C on peut donc pour la plupart des opérateurs
binaires (opérateur (+) qui prend un opérande de chaque côté ex. : i + 3

Opérateurs d’affectation

+= i = i + 3 peut s’écrire i += 3 <<= i = i << 3 peut s’écrire i <<= 3

-= i = i - 3 peut s’écrire i -= 3 >>= i = i >> 3 peut s’écrire i >>= 3

*= i = i * 3 peut s’écrire i *= 3 &= i = i & 3 peut s’écrire i &= 3

/= i = i / 3 peut s’écrire i /= 3 ^= i = i ^ 3 peut s’écrire i ^= 3

%= i = i % 3 peut s’écrire i %= 3 |= i = i | 3 peut s’écrire i |= 3

Les opérateurs d’incrémentation et de décrémentation


Le C comporte deux opérateurs qui servent à additionner ou soustraire 1 à une variable. Donc
l’opérateur ++ ajoute 1 tandis que l’opérateur -- retranche 1 à la variable. Il peut y avoir pour chacun
deux façons de l’utiliser, soit en mode préfixé ou postfixé. La syntaxe est alors la suivante :

Opérateurs d’incrémentation et de décrémentation (posons i = 6 et b = 4)

Préfixé Postfixé

Y= ++i - b Y =7–4=3 Y= i++ - b Y =6–4=2


++i i est augmenté de 1 avant d’effectuer i++ i est augmenté de 1 après avoir effectué
l’opération. Donc i vaut 7 l’opération. Donc i vaut après coup 7

Y= --i - b Y =5–4=1 Y= i-- - b Y =6–4=2


--i i est diminué de 1 avant d’effectuer i-- i est diminué de 1 après avoir effectué
l’opération, donc i vaut 5 l’opération. Donc i vaut après coup 5

Dans un contexte où l’on veut seulement incrémenter une variable sans se servir de sa valeur, comme
par exemple dans :
If (volt == 12){
i++;
}
alors les formes préfixées et postfixées reviennent au même.

André Touchette Page 6/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Mais dans certaines conditions selon le programme, le choix de i++ ou ++i aura une importance sur le
résultat attendu comme dans l’exemple suivant :
Supposons que nous avons un tableau tension contenant 10 int et que l’on veuille mettre à 12 tous ses
éléments.
Première version du programme qui utilise i++.

main() {
int tension[10];
int i = 0;
do {
tension[i++] = 12;
}
while(i <=9);
}

La boucle do-while s’exécute sans condition d’entrée, ici la valeur de i est 0 ce qui conduit à ce que
tension[0] qui est le premier élément du tableau reçoive la valeur 12, suite à cette opération i est alors
incrémenté de 1. L’instruction while vérifie si c’est vrai que i est plus petit ou égal à 9 avant de
recommencer la boucle do-while. Une fois que i sera rendu à 10, on sortira de la boucle. Tous nos
éléments de notre tableau auront été initialisés à 12. Voyons maintenant le comportement de notre
initialisation lorsque l’on utilise ++i au lieu de i++.

Deuxième version du programme qui utilise maintenant ++i.


main() {
int tension[10];
int i = 0;
do {
tension[++i] = 12;
}
while(i <=9);
}
La boucle do-while s’exécute tout de suite; à l’instruction tension[++i] = 12 c’est le i qui sera augmenté
de 1 avant d’effectuer l’affectation de la valeur 12, donc i démarre à 1 ce qui fait que tension[1] = 12.
Par la suite la boucle se continue jusqu’à ce que i soit égal à 10. On obtient alors comme résultat final
que l’élément tension[0] = ? a une valeur indéterminée et que les autres ont comme valeur 12. Vous
voyez bien maintenant l’effet de l’utilisation du mode préfixé et le postfixé.

André Touchette Page 7/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Ordre de préséance des opérateurs


Ordre de préséance des opérateurs

Opérateurs associativité

a() a[b] a->b . De gauche à droite

!a ~a aa++ a-- + - * & sizeof De droite à gauche

* / % De gauche à droite

+ - De gauche à droite

<< >> De gauche à droite

< <= > >= De gauche à droite

== != De gauche à droite

& De gauche à droite

^ De gauche à droite

| De gauche à droite

&& De gauche à droite

|| De gauche à droite

?: De droite à gauche

= += -= *= /= %= &= ^= |= <<= >>= De droite à gauche

, De gauche à droite

Les opérateurs qui figurent sur la même ligne, ont le même niveau de priorité et les lignes sont classées
en ordre décroissant de priorité. Il faut ici bien connaître l’ordre de priorité des opérateurs car lorsque
certains de ceux-ci sont placés dans une équation par exemple, si vous n’avez pas pris le soin de mettre
des parenthèses pour fixer vous-mêmes la priorité des certaines opérations, alors ces dernières seront
exécutées en respectant l’ordre du tableau ci-dessus.

Voici un exemple d’un résultat que l’on pourrait mal interpréter si l’on n’applique pas correctement la
priorité des opérateurs. Posons les variables a, b et c avec les valeurs suivantes 12, 20, 35

Y = a + b * 5 – c = 12 + 20 * 5 – 35 = 77

La multiplication sera effectuée en premier alors le calcul est 20*5 = 100 et par la suite l’addition et la
soustraction sont faites peut importe l’ordre, elles ont la même priorité. Ce qui donne 12+100-35 = 77

André Touchette Page 8/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Les boucles
------------------------------> La boucle for <------------------------------
#include <stdio.h>
#include <stdlib.h>

/*-------------------------------------------------*/
void main(void){
char i,j; // déclaration de variables
int rep;

i = 29; // initialisation de la variable i à 29

for(j=0; j<4 ; j++){


rep = i+j;
printf("Le calcul de rep = %d\n",rep);
i++;
}
}
/*-------------------------------------------------*/

Résultat de l’exécution du programme :


Le calcul de rep = 29
Le calcul de rep = 31
Le calcul de rep = 33
Le calcul de rep = 35

Explication : L’idée derrière l’usage de la boucle « for » est d’exécuter un nombre de fois la plupart du
temps connu, une ou plusieurs instructions qui se retrouvent alors placées entre
l’accolade ouvrante « { « et celle fermante « } » de la boucle « for ». Cette dernière se
divise en trois élément tous séparés par un « ; » le premier correspond à l’initialisation
d’une variable « j » à la valeur que l’on désire selon le fonctionnement recherché dans
notre programme. Le second élément est le test de vérification à savoir si la boucle
« for » doit se répéter ou s’arrêter et poursuivre l’exécution des instructions qui se
retrouveraient à la suite de l’accolade fermante « } ». Ce test de vérification est booléen
(soit VRAI ou FAUX), si c’est VRAI, la boucle peut se poursuivre, sinon elle quitte. Le
troisième élément sert à modifier la variable servant de « compteur » afin qu’elle puisse
un moment donné atteindre une valeur qui mettra fin à la boucle « for », sinon la boucle
n’aurait jamais de fin.
L’analyse du programme se fera en classe.

André Touchette Page 9/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

----------------------------> La boucle while et la boucle do while <----------------------------


#include <stdio.h>
#include <stdlib.h>
/*-------------------------------------------------*/
void main(void){
char i,j; // déclaration de variables

i = 25; // initialisation de la variable i à 25


j = 2; // initialisation de la variable j à 2
while(i > 4){
i = i-j; // nous aurions pu écrire i -= j;
printf("Le calcul de i = %d\n",i);
j++;
}
}
/*-------------------------------------------------*/

Résultat de l’exécution du programme :


Le calcul de i = 23
Le calcul de i = 20
Le calcul de i = 16
Le calcul de i = 11
Le calcul de i = 5
Le calcul de i = -2

Explication : L’idée derrière l’usage de la boucle « while » est d’exécuter une ou plusieurs instructions
qui se retrouvent alors placées entre l’accolade ouvrante « { « et celle fermante « } » du
« while » un nombre de fois qui peut être connu ou non, la condition pour quitter cette
boucle dépendra du résultat du test booléen situé entre parenthèse suivant le « while ».
On peut traduire le « while » par « tant que », donc la boucle va s’exécuter « tant que « le
résultat du test booléen va être « vrai » sinon on quitte celle-ci. Par exemple on pourrait
vouloir vérifier l’état d’un bit dans un registre du microcontrôleur et ne faire que ça « tant
et aussi longtemps » que l’état de ce dernier soit au niveau que l’on désire avant de
poursuivre plus avant l’exécution des instructions suivantes. Dans le programme plus
haut, la boucle « while » va s’exécuter « tant que » la variable « i » sera strictement plus
grande que 4.
La boucle « do while » est similaire à la boucle « while » à la différence majeure que la boucle « while »
doit faire le test booléen avant de pouvoir exécuter les instructions comprises entre ses accolades,
tandis que la boucle « do while » s’exécute au moins une première fois et ensuite elle vérifie si elle doit
boucler à nouveau. La syntaxe est la suivante.

do{
i = i-j;
printf("Le calcul de i = %d\n",i);
j++;
}while(i<4); // ne pas oublier le « ; » à la suite du « while »

André Touchette Page 10/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Les tests conditionnels (if et else if)


------------------------------> le if <------------------------------
#include <stdio.h>
#include <stdlib.h>

/*-------------------------------------------------*/
void main(void){
int rep; // Déclaration de trois variables de type entier
int a,b;

a = 7;
b = 13;

rep = a * b;

if(rep <= 50){


printf("Allo");
}
if(rep > 50 && rep <= 100){
printf("Bonsoir");
}
if(rep > 100){
printf("Bonjour");
}
}
/*-------------------------------------------------*/

Résultat de l’exécution du programme :


Bonsoir

Explication : L’exécution du programme fait en sorte que la variable « rep » aura comme valeur 91, car
rep = a * b = 7 * 13 = 91. Le premier « if » sera testé et le résultat de ce test booléen est
soit VRAI (n’importe quelle valeur différente de 0) ou soit FAUX donc égal à 0, il faut alors
lire le « if » de la manière suivante, est-ce que « rep » est plus petit ou égal à 50, si c’est
vrai alors les instructions comprises dans les accolades { } suivant le « if », seront
exécutées. Ici le premier « if » est faux, donc on passe au second. Le test est maintenant
un « ET » logique entre deux tests conditionnels; il faut alors lire ceci de la façon suivante,
« est-ce que « rep » est plus grand que 50 « ET » est-ce que « rep » est plus petit ou égal à
100 », pour que le résultat soit VRAI, il faut absolument que les deux tests soient VRAI
comme pour un « ET » logique, 1 et 1 = 1. Ici le test sera VRAI car 91 est évidement plus
grand que 50 ET plus petit ou égal à 100. Il s’en suit que les instructions du « if » seront
exécutées et le mot « Bonsoir » va s’écrire à l’écran. Même si le second « if » a été
exécuté, le programme va poursuivre avec l’analyse du troisième « if ». Bien sûr celui-ci
ne sera pas VRAI et le mot « Bonjour » ne pourra s’écrire.

André Touchette Page 11/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

------------------------------> le else if <------------------------------


#include <stdio.h>
#include <stdlib.h>

/*-------------------------------------------------*/
void main(void){
int rep;
int a,b;

a = 7;
b = 13;

rep = a * b;

if(rep <= 50){


printf("Allo");
}
else if(rep > 50 && rep <= 100){
printf("Bonsoir");
}
else if(rep > 100){
printf("Bonjour");
}
else{
printf("Bye");
}
}
/*-------------------------------------------------*/

Résultat de l’exécution du programme :


Bonsoir

Explication : L’exécution du programme donnera bien sûr le même résultat mais il y aura une
économie de temps d’exécution car tous les « if » ne seront pas testés car il y a
maintenant l’ajout du « sinon » correspondant au « else » qui viendra couper court à
l’exploration de chaque « if ». Commençons par le premier « if », celui devra bien sûr être
évalué au départ, étant donné que « rep » vaut 91, le « else if « sera donc évalué. Le test
étant VRAI, le mot « Bonsoir » s’affiche et le programme se termine là-dessus car le
« sinon » ne pourra être VRAI car le « si » l’était déjà avant lui. On voit bien ici que le
programme prendra moins de temps car il n’aura pas tous les tests à effectuer.
À la page suivante, nous voyons l’instruction « switch » qui permet d’une certaine manière
à remplacer ce que plusieurs « if et else if » peut accomplir dans une certaine mesure.

André Touchette Page 12/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

L’instruction (switch est un peu comme un « else if » déguisé)


#include <stdio.h>
#include <stdlib.h>

#define BAS 87 // création d’un alias permettant d’assigner


#define MOYEN 163 // un mot à une valeur ou autre chose
#define HAUT 250 // ce qui fera en sorte que lorsque l’on verra dans
#define RIEN 0 // le programme le mot « BAS », il sera remplacé par 87

/*-------------------------------------------------*/
void main(void){
unsigned char rep,i,j; // déclaration de plusieurs variables
i = 35;
j = 52;

rep = i + j;
switch(rep){ // « rep » doit absolument être un entier
case MOYEN :
printf("Le soleil se leve :");
break;

case RIEN :
printf("Le soleil est couche :");
break;

case BAS :
printf("C'est nuageux :");
break;

case HAUT :
printf("Le soleil brille :");
break;

default :
printf("Oups :");
break;
}
}
/*-------------------------------------------------*/

Résultat de l’exécution du programme :


C’est nuageux :

Explication : L’exécution du programme fait en sorte que la variable « rep » aura comme valeur 87, car
rep = i + j = 35 + 52 = 87. L’instruction « switch » prend alors la valeur de « rep » et va
vérifier dans le cas (case) que si la valeur de « rep » vaut « BAS » soit 87, alors il exécutera
que les instructions situées dans le « case BAS : » jusqu’à ce qu’il rencontre un « break »
qui lui ordonnera alors de quitter l’instruction « switch ». Si aucun « case » ne
correspond, l’instruction « default » vous permet de répondre à toutes les autres
situations.

André Touchette Page 13/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Les fonctions
Le langage C comme la plupart des langages de programmation offrent la possibilité d’écrire des
sections de programme appelé « fonction » que l’on peut par la suite faire appel n’importe d’où dans
l’ensemble de notre programmation. Chaque fonction possède un nom unique qu’on lui attribut et
lorsque l’on a besoin de l’exécuter, il suffit d’inscrire son nom à l’endroit dans le programme où la
séquence d’exécution l’exige.
Il y a différentes manières de déclarer une fonction et par la suite d’en faire l’appel, voici en gros les plus
fréquentes car certaines dépassent le cadre du cours à proprement dit.

1er format de fonction :

Syntaxe de la déclaration
Syntaxe réelle d’appel dans un programme
d’une fonction

void fonction1 (void); fonction1();

Aucun paramètre ne lui est transmis

Nom de la fonction (habituellement écrit en minuscule)

Signifie qu’elle ne retourne aucune valeur suite à son exécution

Exemple d’utilisation d’une fonction dans ce format :

#include <stdio.h>
#include <stdlib.h>

void allume_led(void); // déclaratif de la fonction qui sera


// éventuellement appelée
/*------------------------------------------------------*/
void main()
{
allume_led(); // appel de la fonction
}

/*--------------------------------------------------------*/
/* définition de la fonction avec toutes ses instructions */

void allume_led(void){
char led1,led2;

led1 = 1;
led2 = 1;
}
Lorsque le programme s’exécute, il commence toujours par la fonction main() , on observe alors que la
fonction allume_led() est appelée. Un saut à l’adresse de cette fonction est effectué et les instructions
sont exécutées séquentiellement. Une fois la fonction terminée, le processus revient dans la fonction
main() qui ensuite met fin au programme.

André Touchette Page 14/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

2e format de fonction :

Syntaxe de la déclaration
Syntaxe réelle d’appel dans un programme
d’une fonction

void fonction2 (char valeur) fonction2(45);

Elle reçoit en paramètre une valeur de type « char » soit un


nombre entre 0 et 255 (un char est toujours sur 8 bits)

Nom de la fonction (habituellement écrit en minuscule)

Signifie qu’elle ne retourne aucune valeur suite à son exécution

Exemple d’utilisation d’une fonction dans ce format :

#include <stdio.h>
#include <stdlib.h>

void delai_ms(int valeur); // déclaratif de la fonction qui sera


// éventuellement appelée
/*------------------------------------------------------*/
void main(void){
int i = 10;

while(i){
i--;
delai_ms(1000); // appel de la fonction
}
}
/*------------------------------------------------------*/
void delai_ms(int valeur){
int i;

while(valeur--){
for(i=0;i<400;i++){}
}
}

La fonction main() fait l’appel de la fonction delai_ms(1000) qui reçoit en paramètre l’entier 1000 qui
sera alors utilisé dans cette dernière pour lui indiquer le nombre de fois qu’elle devra faire la boucle
« for » prévue pour durer 1ms. La variable « valeur » déclarée localement dans la fonction delai_ms()
recevra alors le nombre 1000 qui a été passé en paramètre. Le contenu de « valeur » sera utilisé dans la
boucle « while » afin d’effectuer un bouclage qui donnera un délai de 1ms multiplié par ce que contient
« valeur ». Le paramètre passé à la fonction « delai_ms() » peut être un nombre donné directement ou
être le contenu d’une variable de type entier ou même le résultat d’une opération mathématique ou le
résultat de ce que pourrait retourner une fonction passée en paramètre. Les variantes sont
nombreuses.

André Touchette Page 15/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

3e format de fonction :

Syntaxe de la déclaration
Syntaxe réelle d’appel dans un programme
d’une fonction

char fonction3 (void) reponse = fonction3();

Aucun paramètre ne lui est transmis

Nom de la fonction (habituellement écrit en minuscule)

Signifie qu’elle retourne une valeur de type « char » soit un entier de 8 bits

Exemple d’utilisation d’une fonction dans ce format :

#include <stdio.h>
#include <stdlib.h>

char conversion(void); // déclaratif de la fonction qui sera


// éventuellement appelée
/*------------------------------------------------------*/
void main(void){
char reponse;

while(1){
reponse = capteur(); // appel de la fonction et la valeur
// qu’elle retourne est mise dans la
// reponse
}
}

/*------------------------------------------------------*/
char capteur(void){
char lecture;
lecture = PTAD;
lecture >>= 4;

return lecture;
}

La fonction main() fait l’appel de la fonction capteur() continuellement. La valeur que va retourner
cette fonction sera alors placée dans la variable « reponse ». On doit donc lire la ligne « reponse =
capteur(); » comme suit : met dans la variable « reponse » le résultat que retournera la fonction
« capteur() ». Comme on peut le voir, la fonction « capteur() » retourne le contenu de sa variable locale
« lecture » qui sera copié dans la variable « reponse » ultimement

André Touchette Page 16/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

4e format de fonction :

Syntaxe de la déclaration
Syntaxe réelle d’appel dans un programme
d’une fonction

int fonction4 (char valeur) reponse = fonction4(125);

Elle reçoit en paramètre une valeur de type « char » soit un


nombre entre 0 et 255 (un char est toujours sur 8 bits)

Nom de la fonction (habituellement écrit en minuscule)

Signifie qu’elle retourne une valeur de type « int » soit un entier signé de 16 ou 32
bits, selon le microcontrôleur ou microprocesseur utilisé

Exemple d’utilisation d’une fonction dans ce format :

#include <stdio.h>
#include <stdlib.h>

int conversion(char valeur); // déclaratif de la fonction qui sera


// éventuellement appelée
/*------------------------------------------------------*/
void main(void){
int reponse;

while(1){
reponse = conversion(125);
}
}

/*------------------------------------------------------*/
int conversion(char valeur){
int i;

i = (valeur * 3)+32;
return i;
}

La fonction main() fait l’appel de la fonction conversion() continuellement. La valeur que va retourner
cette fonction sera alors placée dans la variable « reponse ». Il faut lors de l’appel de cette fonction lui
passer en paramètre une valeur entière de 8 bits qui sera utilisée pour effectuer des calculs.

André Touchette Page 17/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

5e format de fonction :
Syntaxe de la déclaration
Syntaxe réelle d’appel dans un programme
d’une fonction

int * fonction5 (int *tab) ptr = fonction5(tab);

Elle reçoit en paramètre un pointeur sur des « int »

Nom de la fonction (habituellement écrit en minuscule)

Signifie qu’elle retourne un pointeur sur des « int ». Donc la valeur retournée est
une adresse vers des « int »

Exemple d’utilisation d’une fonction dans ce format, mais avec plusieurs paramètres :

#include <stdio.h>
#include <stdlib.h>

int * extraction(int *tab1, int *tab2, int *tab2, char pn );


/*------------------------------------------------------*/
void main(void){
int tableau[10] ={35,-689,75,32,-125,368,-2000,98,-65,0};
int positif[10];
int negatif[10];
int *pointeur,*ptr1,*ptr2,*ptr3;
ptr1 = tableau;
ptr2 = positif;
ptr3 = negatif;
pointeur = extraction(ptr1,ptr2,ptr3,-1);
}
/*------------------------------------------------------*/
int * extraction(int *tab1, int *tab2,int *tab3,char pn){
int *ptr;

if(pn < 0){


ptr = tab3;
while(*tab1 != 0){
if(*tab1 < 0){
*tab3++ = *tab1++;
}else{
tab1++;
}
}
return ptr;
}else{
ptr = tab2;
while(*tab1 != 0){
if(*tab1 > 0){
*tab2++ = *tab1++;
}else{
tab1++;
}
}
return ptr;
}

André Touchette Page 18/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

La fonction « extraction » effectue le travail suivant : Lors de son appel, on lui passe en paramètre
l’adresse des tableaux d’entiers signés « tableau », « positif » et « negatif ». Vous remarquerez pourtant
que ce ne sont pas les noms des tableaux qui sont utilisés mais des pointeurs sur ces tableaux. Donc le
pointeur « ptr1 » contient l’adresse de « tableau », ensuite « ptr2 » contient celle de « positif » et
finalement « ptr3 » celle du tableau « negatif ». Comme dernier paramètre à l’appel de la fonction
« extraction » le nombre inscrit est une valeur négative comme -1 par exemple, si l’on désire extraire
tous les nombres négatifs contenus dans le tableau « tableau » ou une valeur positive si l’on veut une
extraction des nombres positifs de ce tableau. En fonction du choix d’extraction, le pointeur
« pointeur » déclaré dans le main() recevra après l’exécution de la fonction « extraction », l’adresse du
tableau dans lequel les nombres recherchés auront été recopiés. Nous pourrions par la suite faire
l’impression du contenu de ce qu’il y a dans le tableau ainsi rempli.

NOTE : Il y a deux façons de passer des paramètres à une fonction, par valeur ou par référence. Par
« valeur » cela signifie que c’est le contenu d’une variable ou une valeur directe qui est passé,
tandis que par « référence » c’est l’adresse d’une variable qui est alors passée en paramètre.
Ce que nous appelons un pointeur. Nous verrons en classe de quoi il s’agit.

Les STRUCT
Une structure rassemble une ou plusieurs variables, qui peuvent être de types différents, que l’on
regroupe sous un seul nom pour les manipuler plus facilement. Un exemple simple d’une structure est
la création d’un carnet d’adresses : composé du prénom, du nom de famille, du téléphone et de l’âge
etc… Cette structure recevra un nom qui permet de l’identifier et de la distinguer d’une autre structure.
La création d’une structure vient définir un nouveau type de variable comme pour les « char », « int » et
autres. Tant que l’on ne déclare pas de variable aillant le type de cette structure, celle-ci n’occupe
aucun espace mémoire. On peut le moment voulu déclarer plusieurs variables ayant le type de notre
nouvelle structure et ainsi posséder toutes ces caractéristiques. Voici un exemple de déclaration d’une
structure.

struct carnet { struct carnet {


unsigned char nom[30]; unsigned char nom[30];
unsigned char prenom[20]; unsigned char prenom[20];
unsigned int age; unsigned int age;
unsigned char telephone[15]; unsigned char telephone[15];
}; }ami;

Ici la structure est simplement déclarée et Ici la structure est déclarée et à la


ne prend aucun espace mémoire. La fin on y déclare une variable « ami »
déclaration d’une variable de ce type pourra qui sera du type « struct carnet »
alors être faite ultérieurement.
Si nous faisons cette déclaration de
variable, il faut alors écrire :

struct carnet ami; // on déclare une


//variable ami du type
// struct carnet

La variable « ami » du type «struct carnet » est composé de 4 membres ou éléments. L’espace mémoire
qu’elle occupera sera déterminée par le type des éléments qui la composent. À première vue, il suffit de
calculer la somme du nombre d’octets que prend chaque élément, ce qui donnerait 30+20+4+15 = 69,

André Touchette Page 19/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

mais dans les faits cela n’est pas tout à fait exact. Le compilateur va s’arranger pour faire en sorte que
l’adresse où vont être mis chaque élément, devra arriver sur une frontière qui sera un multiple du type
prenant le plus d’octet soit le « int ». Je m’explique, ici dans notre « struct carnet », il y a des « char » ce
type occupe à la base un octet, tandis que le « int » en occupe quatre. Supposons que l’adresse du
tableau nom[] débute à 448, si on lui ajoute 30 octets l’adresse du dernier octet de nom[] sera 477. Ce
qui conduit à ce que l’adresse du tableau prenom[] débute à 478 et normalement il se terminera à
l’adresse 497. C’est ici que ça change, étant donné que l’élément « age » est un « int » il devra donc
débuter à une adresse qui sera un multiple de 4 (4 octets), si on additionne 30 + 20 = 50 on se rend
compte que 50 n’est pas un nombre divisible par 4, le nombre supérieur le plus près est 52, donc
l’adresse de « age » débutera à l’adresse 500, soit 448+30+20+2 = 500. Par la suite le tableau
telephone[] commencera à l’adresse 504 et se terminera à l’adresse 520 pour que l’ensemble donne un
multiple de 4. En résumé notre variable « ami » occupera au total 30+20+2+4+15+1 = 72 octets.

Utilisation des éléments d’une structure :

Prenons le programme suivant qui place dans la variable « ami » du type struct carnet, pour chaque
élément la composant, une valeur et ensuite d’en faire l’impression.

void main(void){
struct carnet {
unsigned char nom[30];
unsigned char prenom[20];
unsigned int age;
unsigned char telephone[15];
};
struct carnet ami;

printf("\n\nQuel est votre prenom : ");


scanf("%s",ami.prenom);
printf("Quel est votre nom : ");
scanf("%s",ami.nom);
printf("Quel est votre age : ");
scanf("%d",&ami.age);
printf("Quel est votre numero de telephone : ");
scanf("%s",ami.telephone);

printf("\n\n%s %s de %d ans tel:%s\n\n",ami.prenom,ami.nom,ami.age,ami.telephone);


}

Résultat de l’exécution du programme :

Si nous voulions avoir plus d’une information dans notre carnet d’ami, il faudrait alors déclarer d’autres
variables du type « struct carnet » mais comment faire si on veut imprimer tout notre carnet d’amis
mais que chaque ami a sa propre variable cela va devenir lourd surtout pour la création de nouvelles

André Touchette Page 20/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

variable pour chaque ami. La solution sera donc de se créer un tableau de structure afin que tout soit
sous la même rubrique. Voici comment faire : il suffit de déclarer un tableau qui pourra contenir disons
40 structures du type « struct carnet », la syntaxe sera simplement comme suit :

struct carnet ami[40];


Nous pourrons maintenant avoir les coordonnées de plusieurs personnes en lien avec le même tableau
de structures. Le premier copain dans notre liste sera contenu dans la structure ami[0], tandis que le
copain suivant sera dans la structure ami[1] et ainsi de suite. Supposons que nous désirons mettre dans
une variable quelconque l’âge du 5e ami de notre carnet il suffirait d’écrire :

reponse = ami[4].age;

Pour accéder à un membre ou élément d’une structure, il faut mettre un « . » après le nom de la
structure pour spécifier à quel élément on fait allusion.

Les UNION
Une « union » se déclare de la même façon qu’une « struct » mais l’espace mémoire que partage chacun
de ses membres est le même. Voici comment elle se déclare et comment elle fonctionne.

union ordre{ union ordre{


unsigned int nombre_total; unsigned int nombre_total;
unsigned char nombre_separe[4]; unsigned char nombre_separe[4];
}; }valeur;

Ici l’union est simplement déclarée et ne Ici l’union est déclarée et à la fin
prend aucun espace mémoire. La déclaration on y déclare une variable « valeur »
d’une variable de ce type pourra alors être qui sera du type « union ordre »
faite ultérieurement.
Si nous faisons cette déclaration de
variable, il faut alors écrire :

union ordre valeur; // on déclare une


//variable ami du type
// struct carnet

Supposons que la variable « valeur » de type « union ordre » est à l’adresse 2293516, l’élément
« nombre_total » débutera à l’adresse 2293516 pour se terminer à 2293519. Jusqu’ici rien de
particulier, mais ce qui est intéressant dans l’utilisation de l’union, c’est que l’élément
« nombre_separe[] » va lui aussi débuter à l’adresse 2293516, car ils occupent tous les deux le même
espace mémoire, c’est ce qui différencie la « struct » de l’« union ». On peut donc conclure que la
quantité d’octets que prendra la variable « valeur » sera de 4.

Vous vous dites sans doute, quelle est l’utilité d’avoir deux variables à la même place car si j’écris sur
une je modifie l’autre aussi ? Pour vous convaincre, prenez le fichier « mc9s08el32.h » de CodeWarrior,
vous pourrez observer que tous les registres et tous les bits composants ces registres sont déclarés dans
des « union » qui incluent des « struct ». Je vous montre une section de ce fichier portant sur la
déclaration d’une « union » décrivant le PORT A du µC.

André Touchette Page 21/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

/*** PTAD - Port A Data Register; 0x00000000 ***/


typedef union {
byte Byte;
struct {
byte PTAD0 :1; /* Port A Data Register Bit 0 */
byte PTAD1 :1; /* Port A Data Register Bit 1 */
byte PTAD2 :1; /* Port A Data Register Bit 2 */
byte PTAD3 :1; /* Port A Data Register Bit 3 */
byte :1;
byte :1;
byte PTAD6 :1; /* Port A Data Register Bit 6 */
byte PTAD7 :1; /* Port A Data Register Bit 7 */
} Bits;
struct {
byte grpPTAD :4;
byte :1;
byte :1;
byte grpPTAD_6 :2;
} MergedBits;
} PTADSTR;
extern volatile PTADSTR _PTAD @0x00000000;
#define PTAD _PTAD.Byte
#define PTAD_PTAD0 _PTAD.Bits.PTAD0
#define PTAD_PTAD1 _PTAD.Bits.PTAD1
#define PTAD_PTAD2 _PTAD.Bits.PTAD2
#define PTAD_PTAD3 _PTAD.Bits.PTAD3
#define PTAD_PTAD6 _PTAD.Bits.PTAD6
#define PTAD_PTAD7 _PTAD.Bits.PTAD7
#define PTAD_PTAD _PTAD.MergedBits.grpPTAD
#define PTAD_PTAD_6 _PTAD.MergedBits.grpPTAD_6

Dans cette « union », il y a 3 éléments qui la composent, le premier est l’élément « Byte » qui est du
type « byte » portez attention au « B » et « b » ce qui n’est pas la même chose, cette élément occupe 1
octet, le second élément est la « struct » « Bits » qui elle contient 8 éléments occupant chacun un bit et
le troisième est aussi une « struct » nommée « MergeBits » qui possède 4 éléments occupant
respectivement 4 bits, 1, 1 et 2 bits. Comme chacun de ces 3 éléments de l’union vont occuper le même
espace mémoire, soit l’adresse du PORT A à $0000, je pourrai donc être en mesure d’écrire sur le PORT
A avec un seul octet directement ou aller écrire sur chacun des bits séparément en utilisant le nom des
éléments composant les « struct » incluses dans l’ « union ». C’est pourquoi vous êtes en mesure dans
vos programmes en langage C de mettre par exemple le bit 2 du PORT A à 1 en ciblant l’élément de la
« struct » s’occupant du bit 2 en écrivant PTAD_PTAD2 = 1. Je vous montrerai plus avant de quoi il
retourne dans le cours théorique.

Passons maintenant à un exemple concret en examinant le programme suivant.


void main(void){
union ordre{
unsigned int nombre_total;
unsigned char nombre_separe[4];
};
union ordre valeur;

printf("sizeof valeur = %d\n",sizeof valeur);


valeur.nombre_total = 0x9A5BE872;
printf("adresse de nombre_total : %d\n",&valeur.nombre_total);
printf("nombre_total en hexadecimal : %x\n\n",valeur.nombre_total);
printf("nombre_separe[0]=%x\tson adresse %d\n",valeur.nombre_separe[0],&valeur.nombre_separe[0]);
printf("nombre_separe[1]=%x\tson adresse %d\n",valeur.nombre_separe[1],&valeur.nombre_separe[1]);
printf("nombre_separe[2]=%x\tson adresse %d\n",valeur.nombre_separe[2],&valeur.nombre_separe[2]);
printf("nombre_separe[3]=%x\tson adresse %d\n\n",valeur.nombre_separe[3],&valeur.nombre_separe[3]);
printf("C'est une representation en memoire dans le format BIG-ENDIAN\n\n");

André Touchette Page 22/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

printf("Modification du 2e octet le moins significatif\n");


printf("Changeons 0xE8 par 0xAA\n");
valeur.nombre_separe[1] = 0xAA;
printf("nombre_total vaut maintenant : %x\n",valeur.nombre_total);
}

En se référant aux explications précédentes, chaque élément occupe 4 octets en mémoire, mais faisant
partie d’une union, ils occuperont le même espace mémoire. Au début du programme, on fait
l’impression de la dimension en octets qu’occupe la variable « valeur » du type « union ordre », par la
suite on initialise l’élément « nombre_total » faisant partie de « valeur » avec le nombre 0x9a5be872, ce
qui occupe 4 octets. Étant donné que « nombre_total » et « nombre_separe[] » occupent les mêmes
cases mémoires, écrire dans un élément affectera aussitôt l’autre. Lors de l’impression de chaque octet
du tableau « nombre_separe[] », nous obtiendrons séparément le contenu de « nombre_total » ce qui
ne pouvait se faire si on imprimait le contenu de « nombre_total ». De plus on observe que l’octet le
plus significatif de « nombre_total » est 0x9a et qu’il se retrouve à la dernière adresse formant
« valeur ». Ce positionnement en mémoire par le système est nommé « BIG-ENDIAN » du fait que la
partie basse du nombre débute à la première adresse et que la partie haute se termine à la dernière
adresse.

Modifions par exemple seulement le deuxième octet le moins significatif de « nombre_total » soit la
valeur 0xE8 par 0xAA, on se rend vite compte qu’on ne peut le faire en écrivant directement sur
« nombre_total » car nous devrions réécrire exactement les mêmes octets pour tous ceux que l’on ne
veut pas changer, or l’élément « nombre_separe[1] me permet d’y accéder facilement, nous n’avons
qu’à écrire l’instruction suivante et le tour sera joué, « valeur.nombre_separe[1] = 0xAA. Si nous faisons
imprimer par la suite « nombre_total » nous aurons comme résultat ce qui est présenté dans la fenêtre
d’exécution du programme.

Les tableaux de pointeurs et les pointeurs de tableaux


Ces sujets seront traités en classe et des exemples vous seront donnés. Vous aurez sans doute besoin
de ces notions pour accomplir le devoir que vous devez faire en équipe.

André Touchette Page 23/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Les fonctions de traitement des chaînes : « string.h »

Il y a plusieurs fonctions de traitement des chaînes, je vous en énumère quelques unes pour vous
donner un aperçu de leur syntaxe et aussi de leur utilité.

char *strcpy(s,ct) : copie la chaîne « ct » y compris ‘\0’, dans la chaîne « s » et retroune « s ».

char *strcat(s,ct) : concatène la chaîne « ct » à la suite de la chaîne « s » et retourne « s ».

int *strcmp(cs,ct) : compare la chaîne « cs » à la chaîne « ct »; retourne une valeur négative


si « cs < ct », nulle si « cs ==ct », positive si « cs > ct ».

char *strchr(cs,c) : retourne un pointeur sur la première occurrence de « c » dans la chaîne


« cs », ou NULL si « c » ne figure pas dans « cs ».

char * strstr(cs,ct) : retourne un pointeur sur la première occurrence de la chaîne « ct » dans


la chaîne « cs », ou NULL si elle n’y figure pas.

Il y a bien plusieurs autres fonctions dans la bibliothèque standard du langage C, vous pouvez fouiller sur
Internet afin de le découvrir en tapant simplement les noms des en-têtes de la bibliothèque du C
montrées ci-dessous.

Les en-têtes de la bibliothèque C ISO


<assert.h>
Contient la macro assert, utilisée pour aider à détecter des incohérences de données et d'autres
types de bogues dans les versions de débogage d'un programme.
<complex.h>
Pour manipuler les nombres complexes (introduit par C99).
<ctype.h>
Fonctions utilisées pour classifier rapidement les caractères, ou pour convertir entre majuscules
et minuscules de manière indépendante du système de codage des caractères) (character set)
utilisé (ASCII, ISO 8859-1, EBCDIC, etc.).
<errno.h>
Ensemble (ou le plus souvent sous-ensemble) des codes d'erreurs renvoyés par les fonctions de
la bibliothèque standard au travers de la variable errno.
<fenv.h>
Pour contrôler l'environnement en virgule flottante (floating-point) (introduit par C99).
<float.h>
Contient des constantes qui spécifient les propriétés des nombres en virgule flottante qui
dépendent de l'implémentation, telles que la différence minimale entre deux nombres en
virgule flottante différents (xxx_EPSILON), le nombre maximum de chiffres de précision
(xxx_DIG) et l'intervalle des nombres pouvant être représentés (xxx_MIN, xxx_MAX).
<inttypes.h>
Pour des conversions précises entre types entiers (introduit par C99).
<iso646.h>
Pour programmer avec le jeu de caractères ISO 646 (introduit par Amd.1).
<limits.h>
Contient des constantes qui spécifient les propriétés des types entiers qui dépendent de
l'implémentation, comme les intervalles des nombres pouvant être représentés (xxx_MIN,
xxx_MAX).

André Touchette Page 24/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

<locale.h>
Pour s'adapter aux différentes conventions culturelles.
<math.h>
Pour calculer des fonctions mathématiques courantes. C99 a ajouté de nombreuses fonctions
mathématiques, en particulier pour converger avec la norme CEI 559 dite aussi IEEE 754.
<setjmp.h>
Pour exécuter des instructions goto non locales (sortes d'exceptions).
<signal.h>
Pour contrôler les signaux (conditions exceptionnelles demandant un traitement immédiat, par
exemple signal de l'utilisateur).
<stdarg.h>
Pour créer des fonctions avec un nombre variable d'arguments.
<stdbool.h>
Pour avoir une sorte de type booléen (introduit par C99).
<stddef.h>
Définit plusieurs types et macros utiles, comme NULL.

<stdint.h>
Définit divers types d'entiers, c'est un sous-ensemble de inttypes.h (introduit par C99).
<stdio.h>
Fournit les capacités centrales d'entrée/sortie du langage C, comme la fonction printf.

<stdlib.h>
Pour exécuter diverses opérations dont la conversion, la génération de nombres pseudo-
aléatoires, l'allocation de mémoire, le contrôle de processus, la gestion de l'environnement et
des signaux, la recherche et le tri.
<string.h>
Pour manipuler les chaînes de caractères.
<tgmath.h>
Pour des opérations mathématiques sur des types génériques (introduit par C99).
<time.h>
Pour convertir entre différents formats de date et d'heure.
<wchar.h>
Pour manipuler les caractères larges (wide char), nécessaire pour supporter un grand nombre de
langues et singulièrement Unicode (introduit par Amd.1).
<wctype.h>
Pour classifier les caractères larges (introduit par Amd.1).
---------------------------------------------------------------------------------------------------------------------------------------

André Touchette Page 25/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Tableau de conversion par la fonction printf()

CARACTÈRE TYPE DE L’ARGUMENT ; CONVERTI EN

%d, %i int ; notation décimale signée

%o int ; notation octale non signée (non précédée d’un zéro)

%x, %X int ; notation hexadécimale non signée (non précédée de 0x ou 0X)

%u int ; notation décimale non signée

%c int ; un seul caractère, après conversion en unsigned char

char * ; les caractères d’une chaîne sont imprimés jusqu’à rencontrer un ‘\0’
%s
ou jusqu’à avoir imprimé le nombre de caractères indiqué par la précision

double ; notation décimale de la forme [-]mmm.ddd où le nombre de d est


%f donné par la précision. La précision par défaut est 6; si la précision vaut 0, le
point décimal est supprimé.

double ; notation décimale de la forme [-]m.dddddde±xx ou [-]m.ddddddE±xx


%e, %E où le nombre de d est donné par la précision. La précision par défaut est 6; si
la précision vaut 0, le point décimal est supprimé.

double ; l’impression se fait suivant le format %e ou %E si l’exposant est


%g, %G inférieur à -4 ou supérieur ou égal à la précision; sinon suivant %f. Les zéros
ou le point décimal à la fin du nombre ne sont pas imprimés.

void * ; écrit l’argument suivant le format du type de pointeur.


%p
(représentation dépendant de l’implémentation)

int * ; le nombre de caractères écrits jusqu’à présent par cet appel de printf
%n
est écrit dans l’argument. Ne converti pas d’argument.

%% Ne converti pas d’argument ; imprime un %

André Touchette Page 26/27


243-616-EM Intégration de systèmes Cégep Édouard-Montpetit

Tableau de conversion par la fonction scanf()

CARACTÈRE TYPE DE L’ARGUMENT ; CONVERTI EN

&d entier sous forme décimale ; int *

entier , int *. L’entier peut être sous forme octale, s’il est précédé par un 0, ou
&i
hexadécimale, s’il est précédé par 0x ou 0X.

&o entier sous forme octale (précédé ou non d’un zéro) ; int *

&u entier non signé sous forme décimale ; unsigned int *.

&x entier sous forme hexadécimale (précédé ou non de 0x ou 0X) ; int *

caractère ; char *. Les caractères suivants en entrée sont placés dans le


tableau indiqué, jusqu’à atteindre la largeur du champ; par défaut cette valeur
&c vaut 1. N’ajoute pas de ‘\0’. Dans ce cas, les caractères d’espacement ne sont
pas sautés; pour lire le prochain caractère différent d’un caractère
d’espacement, il faut utiliser %1s.

chaîne de caractères ne comportant aucun caractère d’espacement (sans


s guillemets); char *, pointant sur un tableau de caractères assez grand pour
contenir la chaîne et le caractère de terminaison qui lui sera ajouté.

nombre en virgule flottante; float *. Le format d’entrée des nombres de type


float est le suivant : un signe facultatif, une suite de chiffres pouvant
&e, &f, &g
comporter un point décimal et un exposant facultatif comprenant un E ou un
e suivi d’un entier éventuellement signé.

André Touchette Page 27/27

Vous aimerez peut-être aussi