Programmation C pour
systmes embarqus
Sylvain MONTAGNY
[email protected]
Btiment chablais, bureau 13
04 79 75 86 86
Retrouver tous les documents de Cours/TP sur le site
www.master-electronique.com
Prsentation des cours : Sommaire
Cours : 10.5 h en 7 sances
1re partie : Rappel sur le langage C (Exercices de base)
2me partie : La programmation en langage C avance
3me partie : Prsentation du TP : Ralisation dun
algorithme de compression de donnes.
Universit de Savoie
Prsentation TP et examen
TP : 20 h en 5 sances
Le but de ce projet est d'crire un programme de compression de
fichiers textes, sans perte d'information. On demande galement
d'crire un dcompresseur qui devra restaurer le fichier original.
Lalgorithme propos ici est l'algorithme de Huffman.
Une note :
18 points : Examen de TP avec une partie thorique.
2 points proviennent du travail fait en TP
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
Donner lexcution du code suivant :
#include <stdio.h>
#include <stdlib.h>
int main(void){
unsigned char i;
unsigned char tab[5]={1,2,4,8,16};
for (i=0;i<5;i++) {
printf("Le %d element est %d\n",i+1,tab[i]);
} return EXIT_SUCCESS;
}
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
Donner lexcution du code suivant :
#include <stdio.h>
int main() {
int i,j;
for(i=0;i<5;i++){
for(j=5-i;j<5;j++){
printf("++");
}
printf("\n");
}
return EXIT_SUCCESS;
}
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
crire une fonction C calculant la longueur d'une
chane de caractres, donne en argument. Le
prototype de la fonction est le suivant :
int longueur(char *s)
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
crire une fonction C calculant la longueur d'une
chane de caractres, donne en argument.
int longueur(char *s) {
int n = 0;
while (s[n] != '\0') {
n++;
}
return n;
}
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
Soit un texte donn par une chane de caractres. Le
but est de compter le nombre d'occurrences de
chaque lettre minuscule.
Question 1 : Raliser les dclarations suivantes :
Le texte (chane de caractre constante en lettre minuscule)
sera dclar dans un tableau nomm ch . Vous afficherez
la chane de caractre lcran.
Un tableau d'entiers nomm occ permet de compter les
occurrences de chaque lettre de lalphabet. La taille du
tableau est fixe par une constante (nombre de lettre de
lalphabet).
Un pointeur nomm p pour parcourir le texte.
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
#include <stdio.h>
#define NB_LETTRE 26;
void main(void) {
/* dclaration d'une chane <=> tableau de caractres. */
char ch[]="ceci est une chane de test";
/* dclaration d'un pointeur sur une chane de caracteres. */
char *p = ch;
/* dclaration d'un tableau de 26 cases */
int occ[NB_LETTRE];
printf("Chane en mmoire : %s\n",ch);
}
Universit de Savoie
1re partie : Rappel sur le langage C
(exercices de base)
Question 2 : Initialiser le tableau doccurrence zro :
int i=0;
for (i=0; i<NB_LETTRE;i++)
occ[i]=0;
Question 3 : Compter les occurrences jusqu la fin de la chane
de caractre :
while (*p != '\0') {
if ( (*p >= 'a) && (*p <= 'z) ) {
occ[*p-'a'] = occ[*p-'a'] + 1;
}
p++;
}
Question 4 : Afficher le contenu du tableau occ en prcisant la
lettre : le nombre de a est le nombre de b est .
for (i=0; i<nb_lettres; i++)
printf("Nombre de %c : %d\n", 'a'+i,occ[i]);
Universit de Savoie
10
2me partie : La programmation en
langage C avance
Lisibilit du code,
les types de variables,
les typedef,
occupation mmoire,
port des variables,
les oprateurs,
manipulation de registre,
les structures,
les pointeurs,
le main(),
pointeurs,
la pile,
type de fonction,
allocation dynamique,
les options doptimisations la compilation,
les erreurs classiques du C
11
Lisibilit du code C (1)
Exercice :
Raliser un code qui imprime les N premiers lments d'un
tableau dentier A[ ] en insrant un espace entre les lments et
en commenant une nouvelle ligne aprs chaque dixime chiffre.
void main(void){
int A[80],N,i;
scanf("%d",&N);
for (i=0; i<N; i=i+1){
printf("%d", A[i]);
if ((i%10) == 9)
printf("\n");
else
printf(" ");
}
}
//Saisie de N
//Boucle N fois
//Affichage contenu tableau
//Test du 10me chiffre
12
Lisibilit du code C (2)
Rgles respecter :
Mettre des commentaires explicites
Ne pas trop compresser le code
Respecter une homognit dans votre faon de coder.
Dclarer des variables explicites
Organiser la mise en page de votre code, ou respecter
celle dj existante.
Universit de Savoie
13
Lisibilit du code C (3)
Voici une deuxime faon de coder, trs pratique
mais beaucoup moins lisible.
void main(void){
int A[80],N,i;
scanf("%d",&N);
for (i=0; i<n; i++)
printf("%d%c", a[i],(i%10==9)? \n : ' ');
}
Universit de Savoie
14
Lisibilit du code C (4)
Quelques quivalences parfois viter
Op. Fonction
+= Addition et
affectation
-= Soustraction et
affectation
*= Multiplication
et affection
/= Division et
affectation
%= Modulo et
affectation
++ Incrmentation
Exemple
nombre += 5;
Equivalence
nombre=nombre+5
nombre -= 6;
nombre *= 3;
nombre /= 2;
nombre %= 4;
nombre = nombre % 4
nombre++;
nombre = nombre + 1;
-- Dcrmentation nombre--;
nombre = nombre - 1;
y = x++
y = ++x
y
x
x
y
=
=
=
=
Universit de Savoie
x
x + 1
x + 1
x
15
Lisibilit du code C (5)
#include <stdio.h>
main(t,_,a)char*a;{return!0<t?t<3?main(-79,-13,a+main(-87,1_,main(-86,0,a+1)+a)):1,t<_?main( t+1, _, a ):3,main( -94, 27+t, a )&&t == 2 ?_
<13 ?main ( 2, _+1, "%s %d %d\n" ):9:16:t<0?t<-72?main( _,
t,"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+
,/#{l,+,/n{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K
w'K:'+}e#';dq#'l
q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/
+#n';d}rw' i;# ){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw'
iK{;[{nl]'/w#q#n'wk nw' iwk{KK{nl]!/w{%'l##w#' i;
:{nl]'/*{q#'ld;r'}{nlwb!/*de}'c ;;{nl'{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ')
}+}{rl#'{n' ')# }'+}##(!!/"):t<-50?_==*a
?putchar(31[a]):main(-65,_,a+1):main((*a == '/') + t, _, a + 1
):0<t?main ( 2, 2 , "%s"):*a=='/'||main(0,main(-61,*a, "!ek;dc
i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m
.vpbks,fxntdCeghiry"),a+1);}
The International Obfuscated C Code Contest >> http://www.ioccc.org/
Les types de variables (1)
char = 1 octet (signed ou unsigned)
Int, long, double, float dpendent de la cible processeur utilise.
Afin de connatre la taille (en octet) dune variable, on
utilise la fonction sizeof() :
printf("int=%d octets", sizeof(int));
Note : Il nexiste pas de type Boolen en C
Universit de Savoie
17
Les types de variables (2)
Cas dune compilation pour processeur 32 bits
Voir le cas dun compilateur C pour PIC16F ou PIC18F (microchip)
Voir le cas dun compilateur C pour DSP TMS320 (Texas
Instruments) (page suivante)
Universit de Savoie
18
Les types de variables (3)
Universit de Savoie
19
Les types de variables (4)
Donner la reprsentation binaire des nombres suivants :
char a=64;
unsigned char b=64;
char c=128;
unsigned char d=128;
Quel est laffichage des fonctions suivantes?
printf("%d",a);
printf("%d",c);
printf("%u",a);
printf("%u",c+a);
Note : Une dclaration est signed par dfaut gnralement.
Note : %d -> entier signed
/
%u -> entier unsigned
Universit de Savoie
20
Les types de variables (5)
Conversion explicite :
La conversion de type consiste transformer un type de valeur en un
autre, en respectant la syntaxe suivante
(<type>) <expression>
Conversion implicite :
Lorsque les deux oprandes sont de type diffrent, le compilateur
prvoit une conversion implicite suivant l'ordre :
{ char -> int -> long -> float -> double } et { signed ->
unsigned }
Universit de Savoie
21
Les types de variables (6)
Dcrivez le conversion du type, ainsi que les
affectations du code suivant :
int main(void){
int n, m, l;
double d;
d = 5;
n = (int) 3.4;
n = 1;
m = 5;
d = 2;
l = (int) (m / d);
d = n / m;
d = n / ((double) m);
d = 'A' * 6.0 m + 0xA2CL;
return 0;
}
22
Porte des variables
Globale / Locale
Les variables locales sont dclares dans la fonction les utilisant.
les variables globales sont dclares en dbut de programme. Le
linker attribue une adresse fixe et dfinitive ces dernires
(variable globale) pendant toute la dure du programme.
L'utilisation de variables locales amliore considrablement la
lisibilit et la scurit des donnes dans un programme en C.
Une variable locale existe exclusivement pendant lexcution de
la fonction o est dclarer la variable.
Universit de Savoie
23
Classes de stockage et qualificateurs
Classes de stockage
auto : Dfinition automatique pas utilise car implicite.
register : Demande au compilateur dutiliser un registre (plus utile)
static : La variable locale conserve sa valeur
extern : La variable est dclare dans un autre fichier
Qualificateurs
const : Spcifie une variable non modifiable
volatile : Limite les effets de loptimisation sur la variable
Universit de Savoie
24
Classe de stockage et qualificateur
classe auto
Cette classe nest pas utilis car elle est implicite pour les
variables locales. En effet, Les variables locales sont par
dfaut "automatiques" , cres l'entre de la fonction
qui les dclare et dtruites la sortie. Pour cela elles
sont ranges dans la pile.
void f(void) {
auto int j = 0;
printf("j vaut %d",j);
}
void f(void) {
int j = 0;
printf("j vaut %d",j);
}
void main(void) {
f();
}
Mais jamais utilise
. . .
25
Classe de stockage et qualificateur
classe static
La classe static permet une variable locale dtre persistante et donc
de conserver sa valeur pendant les appels successifs de la fonction.
void f(void) {
static int i = 0; /* i ne sera initialis quune fois*/
int j = 0; /* j sera initialis chaque fois */;
i++;
j++;
printf("i vaut %d et j vaut %d.\n", i, j);
}
void main(void) {
f();
f();
}
Note : La classe static sur une variable globale ou une fonction aura
pour objectif de privatiser lobjet au fichier o elle est dclare. Cest-dire quelle ne pourra pas tre utilise depuis un autre fichier.
Classe de stockage et qualificateur
classe extern (1)
extern : permet de spcifier que la variable a t dclar dans un
autre fichier.
/* File : ext.c */
void next(void);
void next1(void);
int a1=1; /* definition of external (non static)*/
void main(void){
a1=2;
printf("a1=%d\n",a1);
next();
next1();
printf("a1=%d\n,a1);
}
27
Classe de stockage et qualificateur
classe extern (2)
/* File file1.c */
/* File file2.c */
int b1=0;
extern int a1;
void next(void){
char a1;
a1='a';
b1=77;
}
void next1(void){
float b1;
b1=19.2;
a1=13;
}
Si on omet le terme extern, une nouvelle variable est
crer avec une nouvelle allocation mmoire.
28
Classe de stockage et qualificateur
classe register
On peut demander au compilateur de ranger une variable trs
utilise dans un registre, laide de la classe register. Le nombre
de registres tant limit, cette requte ne sera satisfaite que sil
reste des registres disponibles. Cette technique permettant
dacclrer les programmes a aujourdhui perdu tout son intrt
grce aux performances des optimiseurs de code intgrs au
compilateur.
Documentation du compilateur MikroC :
Universit de Savoie
29
Classe de stockage et qualificateur
classe register
Le C dfinit des qualificateurs pouvant influer sur une
variable :
const : pour dfinir une variable dont la valeur ne doit jamais
changer ;
volatile : dsigne une variable dont les accs ne doivent pas
tre optimiser par le compilateur. Cette variable sera relue
depuis son emplacement dorigine chaque accs. En effet,
cela est important lorsque dautre sources (priphrique
matriel, processus, etc) accde la variable en mme temps
que notre programme.
Une variable peut avoir plusieurs qualificateurs
Universit de Savoie
30
Classe de stockage et qualificateur
Qualificateur const
Le qualificateur const indique au compilateur que la valeur de la variable
ne doit pas changer. Il est donc impratif d'assigner une valeur la
dclaration de la variable, sans quoi toute tentative de modification
ultrieure entranera une erreur de la part du compilateur :
tudier les codes suivants :
const int i = 0;
i = 1;
void fonction( const char * pointeur ) {
pointeur[0] = 0;
pointeur = "Nouvelle chane de caractres";
}
char * const pointeur = "Salut tout le monde !";
pointeur = "Hello world !";
const char * const pointeur = "Salut tout le monde !";
pointeur = "Hello world !";
pointeur[0] = 0;
Universit de Savoie
31
Classe de stockage et qualificateur
Qualificateur volatile
int * pReg = (int *) 0x 1234;
while (* pReg == 0) {
Le compilateur va optimiser la boucle while en considrant
que la lecture de *pReg nest jamais modifie. En ralit,
elle peut tre modifie par :
Un priphrique dentre/sortie mapp en mmoire
Une interruption
Une autre tche
Universit de Savoie
32
valuation des expressions boolennes (1)
Le C ne possde pas de type boolen ddi. Dans ce langage,
n'importe quelle valeur diffrente de zro est considre vraie,
zro tant considr comme faux. Ce qui veut dire que n'importe
quelle expression peut tre utilise l'intrieur des tests (entier,
rels, pointeurs, tableaux, etc.). Cela peut conduire des
expressions pas toujours trs claires, comme :
int a;
a = une_fonction();
if (a) { /* ... */ }
On prfrera :
int a;
a = une_fonction();
if (a != 0) { /* ... */ }
Attention :
int a = 0; b = 2;
if (a = b) { /* Le code qui suit sera toujours excut ... */ }
Universit de Savoie
33
valuation des expressions boolennes (2)
Les oprateurs logiques de comparaisons (&& et ||, similaires
smantiquement leur quivalent binaire & et |) ont une
excution totalement diffrente.
Dans le cas du ET logique (&&), si l'oprande gauche s'value
faux (valeur zro), on sait dj que le rsultat du ET sera faux et
donc ce n'est pas la peine d'valuer l'oprande droite. De la
mme manire si l'oprande gauche d'un OU logique (||) est
valu vrai, le rsultat sera aussi vrai (valeur !=0) et donc
l'valuation de l'oprande droite est inutile.
if (z != 0 && a / z < 10)
{
printf("Tout va bien\n");
}
Universit de Savoie
34
Les manipulations de bits (1)
Les manipulations de bits sont beaucoup utilises dans
lembarqu. Pour contrler un priphrique matriel,
on retrouve des registres de 8, 16 ou 32 bits quil faut
modifier.
Mettre 1 le bit 4 de a :
unsigned int a = 0x000F; /* 0000 0000 0000 1111 */
Mettre zro le bit 3 de a :
unsigned int a = 0x000F; /* 0000 0000 0000 1111 */
Faire une fonction int set_bit(int mot, int nbr) qui
retourne le mot modifi lemplacement nbr.
35
Les manipulations de bits (1)
Les manipulations de bits sont beaucoup utilises dans
lembarqu. Pour contrler un priphrique matriel,
on retrouve des registres de 8, 16 ou 32 bits quil faut
modifier.
Mettre 1 le bit 4 de a :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */
unsigned b = 0x0010; /* 0000 0000 0001 0000 */
unsigned c = a | b; /* 0000 0000 0001 1111 soit 0x001F */
Mettre zro le bit 3 de a :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */
unsigned b = 0xFFF7; /* 1111 1111 1111 0111 */
unsigned c = a & b; /* 0000 0000 0000 0111 soit 0x0007 */
Universit de Savoie
36
Les manipulations de bits (2)
Tester si le bit 2 de a est 1 :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */
Tester si le bit 3 de a est 1 et si le bit 15 est 0 :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */
37
Les manipulations de bits (2)
Tester si le bit 2 de a est 1 :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */
if (a & (1 << 2)) {
printf("bit 2 = 1");
}
else {
printf("bit 2 = 0");
}
Tester si le bit 3 de a est 1 et si le bit 15 est 0 :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */
if ( a & (1 << 3)!=0
&&
a&(1<<15)==0 ) {
printf("bit 2 = 1 et bit 15=0");
}
else {
printf("bit 2 = 1 et bit 15=0 nest pas vrifi");
}
38
Le main()
Le main() est le point dentre dune application. Dans
un systme embarque sans systme dexploitation, le
point dentre du programme sera prcis dans la
phase ddition de liens par linitialisation du vecteur
dinterruption nomm RESET.
Universit de Savoie
39
A quoi sert un pointeur ?
Universit de Savoie
40
Les tableaux (1)
Un tableau est un regroupement conscutif de
donne de mme type et de taille fixe.
// Tableau 1 dimension
// Tableau 2 dimensions
void main(void){
void main(void){
int tableau[4];
int i;
for(i=0;i<4;i++){
tableau[i]=0;
int tableau[4][3];
int i,j;
for(i=0;i<4;i++){
for(j=0;j<3;j++){
tableau[i][j]=0;
}
}
}
}
Universit de Savoie
41
Les tableaux (2)
tableau[0]
tableau[1]
tableau[2]
tableau[3]
tableau[0][0]
tableau[0][1]
tableau[0][2]
tableau[1][0]
tableau[1][1]
tableau[1][2]
tableau[2][0]
tableau[2][1]
tableau[2][2]
tableau[3][0]
tableau[3][1]
tableau[3][2]
Universit de Savoie
42
Les tableaux (3)
Passage de tableaux en paramtre des fonctions.
Un tableau nest jamais pass en paramtre, cest son
adresse qui est fournie.
Universit de Savoie
43
Organisation logicielle (1)
0xFFFFFFFF
stack
SP (Stack Pointer)
address space
heap
(dynamically allocated)
data segment
Data : (static and global)
0x00000000
code segment
(=program)
Universit de Savoie
PC (Program Counter)
44
Organisation logicielle (2)
Code segment : Emplacement ou se trouve le code compil (programme)
Data segment :
Data : contient toutes les variables static et globales
(initialises ou non)
Heap : Le tas est gr dynamiquement. Cest une zone de donne qui
grossi la rservation de zone mmoire (malloc) et qui se rduit lors
de la libration (free).
Stack : Cest une zone de stockage de type LIFO. Elle contient les
adresses de retour des fonctions et les variables locales.
Universit de Savoie
45
Organisation logicielle (3)
Imposer une adresse physique pour une variable ou une
constante
Les registres des microcontrleurs sont des adresses imposes
par le concepteur du C, or le linker d'un compilateur C a le
contrle total des adresses, il choisit o sont ranges variables et
constantes. On peut aussi imposer une adresse une variable.
Attention, il faut tre certain que vous soyez le seul utiliser
cette adresse pour ne pas crer derreur de segmentation.
char c;
void main (void){
*(unsigned char *)0x80 = 0xAA;
c= *(unsigned char *)0x80;
46
Organisation logicielle (4)
Directive du linker
Il est possible de prciser lditeur de lien lendroit exact ou nous
souhaitons que le code, les variables ou les constantes seront
positionnes. Exemple : Pour le linker MikroC, on utilise les directives
suivantes :
Directive absolute : Directive absolute specifies the starting address in RAM for a
variable or a starting address in ROM for a constant..
Directive org : Directive org specifies a starting address of a routine in ROM.
Directive org is appended to the function definition.
Directive orgall : If the user wants to place his routines, constants, etc, above a
specified address in ROM, #pragma orgall directive should be used.
Directive funcorg : You can use the #pragma funcorg directive to specify the
starting address of a routine in ROM using routine name only.
47
Optimisation du code (1)
Dans le contexte de lembarqu, il est important de connatre les
options de compilation doptimisation. Il y a en effet un compromis
trouver entre la taille de lexcutable produit et le temps dexcution.
Universit de Savoie
48
Optimisation du code (2)
Option -O0 (niveau 0)
Option -O1 (niveau 1)
Allocates variables to registers
Performs loop rotation
Eliminates unused code
Simplifies expressions and statements
Performs all -O0 optimizations, and:
Removes unused assignments
Eliminates local common expressions
Option -O2 (niveau 2) (default optimization level)
Performs all -O1 optimizations, and:
Performs loop optimizations
Universit de Savoie
49