Beruflich Dokumente
Kultur Dokumente
Chap 13T
Langage C et Gestion des Entres/Sorties
Rsum de Thorie
Version prliminaire
Deuxime Anne
Programme de Formation des Techniciens
Spcialiss en lectronique
DIRECTION DE LA RECHERCHE ET INGENIERIE DE LA FORMATION
Septembre 1996
Rsum de Thorie
RDACTION
Robert Pesant
DESSINS ET CONCEPTION GRAPHIQUE
Robert Pesant
RVISION TECHNIQUE
Robert Pesant
RVISION LINGUISTIQUE
Franois Gaudreau
COMMISSION DE VALIDATION
Formateurs de lOFPPT
Fonctions
Page 2
OFPPT/TECCART
Rsum de Thorie
Fonctions
Page 3
OFPPT/TECCART
Fonctions
Fonctions et Standard ANSI
Quest-ce quune fonction?
Une fonction est un ensemble d'instructions et de variables regroupes dans un bloc pour
effectuer une tche spcifique.
Le rle premier d'une fonction est d'viter l'usager de rpter le mme code en diffrents
endroits du programme. Lorsque le code de la fonction sera crit et que l'usager lui aura attribu
un identificateur, c'est--dire un nom, il pourra en faire l'appel dans son programme aussi souvent
que ncessaire, comme c'est le cas pour des fonctions de la bibliothque de Borland C++ tels que
printf() et getch().
Par l'usage des fonctions, la programmation devient structure. Le programme principal, c'est-dire la fonction main(), pourra se construire partir d'un modle prdfini et se composer
presque exclusivement d'appels de fonctions. Il n'en sera que plus facile rdiger, comprendre,
dpanner et entretenir.
Pour rendre une fonction indpendante de la fonction main() ainsi que de toutes les autres
fonctions, le langage C permet l'usage de variables "prives". Ces variables dites locales ne sont
accessibles que par la fonction o elles sont dfinies. L'usager peut donc utiliser les identificateurs
de son choix, mme s'il les a dj utiliss ailleurs dans une autre fonction. Nous reviendrons sur
cette notion importante vers la fin de ce chapitre.
Pour changer des donnes avec le programme qui l'appelle, une fonction peut accepter
plusieurs paramtres mais ne peut retourner qu'une seule et unique valeur.
Pour manipuler correctement une fonction, il faut savoir...
1.
la dfinir,
2.
la dclarer
3.
et en faire l'appel.
Deux notions fondamentales sont ncessaires pour y parvenir:
4.
le prototype de fonction, adopt par le Standard ANSI;
5.
la technique du passage de paramtres par les valeurs.
Prototype de fonction
Le prototype d'une fonction est compos de trois lments crits sur une seule ligne:
6.
le type de donne de la valeur retourne;
7.
l'identificateur de la fonction;
8.
le type de donne et l'identificateur de chaque paramtre, spars par une virgule et
encadrs par une paire de parenthses.
Prenons comme exemple une fonction qui attend le choix de l'usager lorsqu'on lui prsente un
menu. Son prototype peut s'crire comme suit: int get_choix(void). Cette fonction se nomme
get_choix. Son rle est de retourner, sous forme d'un int, le code ASCII de la touche presse
par l'usager. Comme l'information recueillie par cette fonction provient directement du clavier,
elle n'a besoin d'aucun paramtre: on retrouve donc le mot-cl void entre ses parenthses.
Examinons maintenant le prototype d'une fonction qui affiche les codes ASCII compris entre
deux valeurs spcifies par l'usager: void affi_ascii(int code_min, int code_max). La fonction
affi_ascii affiche des caractres l'cran; elle n'a donc pas de valeur numrique retourner au
programme d'appel; c'est ce qui justifie l'emploi du mot-cl void devant son identificateur. Par
contre, cette fonction a besoin de connatre les codes de dbut et de fin qu'elle doit afficher: le
premier paramtre, de type int, est le code initial identifi par code_min; le deuxime paramtre,
galement de type int, est le code final code_max.
Sans mme connatre comment ces deux fonctions vont accomplir leur boulot respectif, nous
avons dj une trs bonne ide de la faon de les utiliser: entre autres choses, il ne faut pas passer
affi_ascii() des variables de type double!
Le prototype de fonction est une nouveaut du langage C introduite par le Standard ANSI. C'est
l'outil qu'utilise le compilateur pour dtecter et signaler par des avertissements (warnings) que
l'usager n'utilise pas les bons types de donnes dans le passage de paramtres.
Dfinition de fonction
Une dfinition de fonction se compose:
9.
du prototype de la fonction;
10. du bloc d'instructions.
Voici la dfinition de la fonction get_choix():
int get_choix(void)
{
int choix;
do
{
gotoxy(63, 11); putch('*'); gotoxy(63, 11);
choix = getche();
}
while(CLE_INTERDITE);
}
return(choix);
Aprs la dfinition de la variable choix, la boucle do ... while() effectue le verrouillage explicite
des touches interdites. L'expression tester est dcrite par la directive suivante:
#define CLE_INTERDITE !((choix == '1') || (choix == '2') || (choix == ESC)) .
Lorsque l'usager choisit une touche permise, 1, 2 ou Esc, le code ASCII dpos dans choix par
getche() est affich l'cran puis transfr ou retourn au programme d'appel par l'instruction
return(choix);. La variable choix a t obligatoirement dfinie de type int, pour tre conforme
au type de donne spcifi par le prototype de la fonction.
L'excution d'une fonction peut se terminer de deux faons diffrentes: par la rencontre de
l'accolade dlimitant la fin du bloc de la fonction ou par l'excution de l'instruction return.
Voyons maintenant la dfinition de la fonction affi_ascii():
void affi_ascii(int code_min, int code_max)
{
int i;
gotoxy(1, 17);
if((code_min < 0) || (code_min > 255) || (code_max < 0) || (code_max > 255))
{
puts("ERREUR!!! Au moins un des deux codes n'est pas compris entre 0 et 255.");
puts("Vous devez recommencer...");
return;
}
if(code_max < code_min)
{
puts("ERREUR!!! Le code final est plus petit que le code initial.");
puts("Vous devez recommencer...");
return;
}
Les deux paramtres, que requiert cette fonction, sont automatiquement dfinis par le prototype
qui prcde le bloc d'instructions. Seule la variable i, qui n'est pas un paramtre, est dfinie dans
le bloc de la fonction par l'instruction int i;.
Puis, deux instructions if vrifient la validit des codes ASCII de dbut et de fin que reoit la
fonction par l'intermdiaire de ses paramtres. Si l'un ou l'autre des codes est infrieur ASCII 0
ou suprieur ASCII 255, ou si le code de fin est infrieur au code de dbut, un message
d'erreur appropri est affich. L'excution de la fonction est alors interrompue par l'instruction
return;. tant donn que la fonction affi_ascii() ne retourne rien au programme d'appel, le motcl return doit donc tre utilis seul, sans aucune expression, pour pouvoir terminer la fonction
ailleurs qu' l'accolade de fin de bloc.
Par contre, si les codes de dbut et de fin sont valides, une boucle for affiche les caractres
ASCII dlimits par ces deux valeurs. L'excution de la fonction se termine alors l'accolade de
fin de bloc.
Dclaration de fonction
Une dclaration de fonction est constitue:
11. du prototype de la fonction;
12. suivie d'un point virgule.
La dclaration d'une fonction doit ncessairement se faire avant l'instruction d'appel. Dans
l'exemple qui suit, les dclarations de get_choix() et affi_ascii() prcdent la dfinition de la
fonction main() qui utilise ces deux fonctions:
La dclaration d'une fonction indique au compilateur comment prparer le code objet (code
machine) qui permettra le saut la sous-routine correspondant cette fonction. L'appel de cette
fonction peut alors tre fait mme si sa dfinition, c'est--dire son code, apparat plus loin dans le
programme.
Une dclaration de fonction ne gnre pas de code objet. Elle ne peut donc pas remplacer la
dfinition de fonction. Par contre, la dfinition de fonction peut servir de dclaration, si elle
prcde l'appel de cette fonction:
Types de fonctions
La Tableau 6 -1 prsente les quatre types de fonctions que l'on peut rencontrer.
T AB L E AU 6-1: L E S
Type
1
2
3
4
T Y P E S D E F O N C T I ON S
Valeur retourne
Aucune
Une seule
Aucune
Une seule
Paramtres
Aucun
Aucun
Un ou plusieurs
Un ou plusieurs
menu
get_choix
affi_ascii
mise_a_echelle
(void);
<--------------------------------------------------(void);
<--------------------------------------------------(int code_min, int code_max);
<----------------------------(double courant, double portee_min, double portee_max);
<---
Type
Type
Type
Type
1
2
3
4
Appel de fonction
Pour faire l'appel d'une fonction de type 1, il suffit d'crire son nom, suivi de parenthses vides et
d'un point virgule:
Fonction de l'usager
Fonction de la bibliothque
menu();
clrscr();
Dans le cas du type 2, il faut au pralable dfinir une variable de mme type que la valeur
retourne pour pouvoir la rcuprer la fin de l'excution de cette fonction:
Fonction de l'usager
Fonction de la bibliothque
int choix;
int touche;
choix = get_choix();
touche = getch();
Lors de son appel, une fonction de type 3 doit recevoir des valeurs numriques par l'intermdiaire
de ses paramtres. Ces valeurs peuvent tre des variables ou des constantes, en autant qu'elles
soient du mme type de donne que les paramtres:
Fonction de l'usager
Fonction de la bibliothque
gotoxy(15, 10);
affi_ascii(ascii_min, ascii_max);
Enfin, l'appel d'une fonction de type 4 combine les techniques utilises pour le type 2 et le type 3:
Fonction de l'usager
Fonction de la bibliothque
c_maj = toupper(c_min);
2.
3.
4.
FONCTION.C
==========
Robert Pesant
22/02/1993
25/04/1995
V1.2
COURS_13T
\CHAP.007\FONCTION.C
Programme de dmonstration qui utilise des fonctions dfinies par l'usager.
<stdio.h>
<conio.h>
<string.h>
<process.h>
<dos.h>
MENU_1
MENU_2
MENU_3
MENU_4
MENU_5
""
" Programme de dmonstration "
" contenant des fonctions
"
"
rdiges par l'usager
"
""
#define
#define
#define
#define
MENU_6
MENU_7
MENU_8
MENU_9
#define
#define
#define
#define
#define
#define
#define
RETOUR
ASCII_1
ASCII_2
ECHELLE_1
ECHELLE_2
ECHELLE_3
ECHELLE_4
#define
#define
#define
#define
CODE_ASCII
TX_4_20_MA
ESC
CLE_INTERDITE
'1'
'2'
27
!((choix == '1') || (choix == '2') || (choix == ESC))
< 1 >"
< 2 >"
<Esc>"
< * >"
menu
get_choix
clr_lines
affi_ascii
mise_a_echelle
(void);
(void);
(int y);
(int code_min, int code_max);
(double courant, double portee_min, double portee_max);
void main(void)
{
int choix, ascii_min, ascii_max;
double courant, temperature;
clrscr();
menu();
do
{
choix = get_choix();
switch(choix)
{
case CODE_ASCII:
gotoxy(1, 15); printf(ASCII_1);
scanf("%d", &ascii_min); fflush(stdin);
gotoxy(41, 15); printf(ASCII_2);
scanf("%d", &ascii_max); fflush(stdin);
affi_ascii(ascii_min, ascii_max);
break;
case TX_4_20_MA:
gotoxy(1, 15); puts(ECHELLE_1);
gotoxy(1, 16); puts(ECHELLE_2);
gotoxy(1, 18); printf(ECHELLE_3);
scanf("%lf", &courant); fflush(stdin);
gotoxy(1 + strlen(ECHELLE_3), 18);
printf("%6.2f mA", courant);
if((courant < 4.0) || (courant > 20.0))
{
puts(" (...???)");
}
temperature = mise_a_echelle(courant, -25.0, 75.0);
gotoxy(1, 19); printf(ECHELLE_4);
printf("%6.2f C", temperature);
break;
case ESC:
clrscr(); exit(0);
}
/* Fonction:
* ========
*
* Description:
*
* Paramtres:
*
* Valeur/retour:
*/
void menu(void)
{
gotoxy(41 gotoxy(41 gotoxy(41 gotoxy(41 gotoxy(41 -
gotoxy(41
gotoxy(41
gotoxy(41
gotoxy(41
menu()
======
Affiche le menu du programme
1. Aucun
1. Aucune
strlen(MENU_1
strlen(MENU_2
strlen(MENU_3
strlen(MENU_4
strlen(MENU_5
)/2,
)/2,
)/2,
)/2,
)/2,
1);
2);
3);
4);
5);
puts(MENU_1
puts(MENU_2
puts(MENU_3
puts(MENU_4
puts(MENU_5
);
);
);
);
);
strlen(MENU_6
strlen(MENU_7
strlen(MENU_8
strlen(MENU_9
);
);
);
);
/* Fonction:
* ========
*
* Description:
*
*
* Paramtres:
*
* Valeur/retour:
*/
get_choix()
===========
Attend et retourne le choix de l'usager.
Les touches interdites du clavier sont verrouilles.
1. Aucun
1. Le code ASCII du choix de l'usager
int get_choix(void)
{
int choix;
do
{
gotoxy(63, 11); putch('*'); gotoxy(63, 11);
choix = getche();
}
while(CLE_INTERDITE);
}
return(choix);
/* Fonction:
* ========
*
* Description:
*
*
* Paramtres:
*
* Valeur/retour:
*/
clr_lines()
===========
Efface le bas de l'cran en faisant remonter le texte
partir de la ligne choisie par l'usager.
1. La ligne partir de laquelle on efface l'cran.
1. Aucune.
void clr_lines(int y)
{
int i;
gotoxy(1, y);
for(i=y; i<=25; i++)
{
delline();
delay(50);
}
/* Fonction:
* ========
*
* Description:
*
*
* Paramtres:
*
*
* Valeur/retour:
*/
affi_ascii()
============
Affiche les codes ASCII demands par l'usager
et compris entre 0 et 255.
1. Le code ASCII initial qui doit tre affich.
2. Le code ASCII final qui doit tre affich.
1. Aucune.
/* Fonction:
* ========
*
* Description:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* Paramtres:
*
*
*
* Valeur/retour:
*/
mise_a_echelle()
================
Effectue la mise l'chelle d'un transmetteur 4-20 mA
en fonction des portes minimale et maximale de son
tendue de mesure.
Exemple: Transmetteur de temprature 4-20 mA dont l'tendue
de mesure est comprise entre -25 C et +75 C.
20 mA ----------- 75 C
<-- porte maximale
B
I ----------- T
<-- grandeur mesure
C
4 mA ----------- -25 C <-- porte minimale
Calcul de mise l'chelle:
A/B = C/D
(T - (-25))/(75 - (-25)) = (I - 4)/(20 - 4)
(T + 25)/100 = (I - 4)/16
return(grandeur);
16.
je_fais_tout_a_moi_tout_seul(void);
Excutez le programme FONCTION.EXE. Vous devriez obtenir des rsultats semblables ceux
de la Figure 6 -1.
F I G U R E 6-1: E X C U T I ON
DE
F O NC T I O N . E X E
2.
3.
Placez la curseur sur l'instruction affi_ascii(ascii_min, ascii_max); qui fait partie de case
CODE_ASCII de l'instruction switch ... case de la fonction main().
4.
5.
6.
7.
Cet exercice confirme qu'une variable locale de classe de stockage automatique n'est visible que
de la fonction o elle est dfinie.
Mais une question se pose. Comment les fonctions peuvent-elles manipuler et s'changer des
donnes si leurs variables locales passent leur temps apparatre et disparatre continuellement?
La rponse sera apporte par la technique du passage des paramtres par les valeurs.
Pour faciliter la comprhension et l'apprentissage de cette technique, nous introduirons d'abord le
modle des rcipients pour reprsenter plus concrtement les variables.
Variables et modle des rcipients
Une variable peut tre reprsente par un rcipient dont la dimension est proportionnelle son
type de donne. Le rcipient lui-mme correspond la rgion mmoire occupe par la variable et
son emplacement sur la tablette de rangement est l'adresse de cette variable. L'identificateur et la
valeur de la variable sont associs respectivement l'tiquette colle sur le rcipient et son
contenu.
La Figure 6 -2 prsente ce modle pour des variables de type char, int et double.
F I G U R E 6-2: L E
menu
get_choix
affi_ascii
mise_a_echelle
(void);
(void);
(int code_min, int code_max);
(double courant, double portee_min, double portee_max);
En examinant, pour chacune d'elles, les paramtres et le type de donne de la valeur retourne, on
peut dduire quelles sont les tapes ncessaires leur excution respective:
menu() ------------>
get_choix() ------->
affi_ascii() ------>
mise_a_echelle() -->
tape 2 seulement,
tapes 2 et 3,
tapes 1 et 2,
tapes 1, 2 et 3.
Comme l'excution de mise_a_echelle() implique les trois tapes, ce sera notre fonction cobaye
pour illustrer le mcanisme de passage des paramtres par les valeurs.
Reportez-vous la Figure 6 -2. Les fonctions peuvent tre considres comme des
compartiments spars par un mur qui les rend invisibles les unes par rapport aux autres.
Dans main(), il y a deux rcipients de type double, courant et temperature. Ce sont assurment
des variables locales puisqu'elles sont dfinies l'intrieur des accolades de main(). Cette
fonction contient galement deux constantes relles reprsentant respectivement les portes
minimale et maximale de l'tendue de mesure du transmetteur 4-20 mA: -25.0 C et 75.0 C.
Du ct de la fonction mise_a_echelle() se trouvent quatre rcipients de type double: les trois
paramtres de la fonction, courant, portee_min et portee_max, ainsi que la variable grandeur.
Comme toutes les variables du programme sont locales, elles sont invisibles d'une fonction
l'autre. Mme si l'on retrouve un rcipient courant dans chacune des deux fonctions, il n'y a pas
de risque de confusion: ce sont deux rgions mmoire bien distinctes.
L'appel de la fonction mise_a_echelle() s'effectue dans main() par l'instruction suivante:
temperature = mise_a_echelle(courant, -25.0, 75.0);
L'excution de cette fonction dbute par l'tape du passage des paramtres par le programme
d'appel, ici la fonction main(). Remarquez qu'entre les parenthses de mise_a_echelle() se trouve
dans l'ordre courant, -25.0 et 75.0. Cette variable et ces deux constantes appartiennent la
fonction main(). Leurs positions respectives dans les parenthses correspondent aux positions de
courant, portee_min et portee_max, les trois paramtres de mise_a_echelle().
Selon notre modle, le passage des paramtres se droule comme ceci.
22. On prend le rcipient courant de main(), dont le contenu est 16.0, et on l'approche de la
fentre ddie au passage des paramtres.
23. La fonction mise_a_echelle() prsente automatiquement le rcipient de son premier
paramtre. Dans ce cas, l'tiquette sur chaque rcipient est la mme, mais personne
de chaque ct n'est au courant. Ce qui est primordial toutefois, c'est que les deux
rcipients soient de la mme dimension; sinon, il y a risque de dbordement!
24.
25.
F I G U R E 6-3: L E
L'tape 1 est maintenant franchie. Passons l'tape 2, l'excution des instructions de cette
fonction. L'instruction la plus importante de mise_a_echelle() effectue le calcul de la grandeur
physique mesure par le capteur du transmetteur en fonction de la valeur de son courant:
grandeur = ((portee_max - portee_min)*(courant - 4.0)/16.0) + portee_min;
Pour un courant de 16.0 mA, le contenu du rcipient grandeur est 50.0 C.
La troisime tape de l'appel de mise_a_echelle() consiste retourner cette valeur la fonction
d'appel, main(). L'instruction requise est:
return(grandeur);