Notes sur le langage C
Date de publication : 29 avril 2009
I. C'est quoi l'algorithmique ?
II. Déclarations ? Définitions ?
II-A. Déclaration
II-B. Définition
III. Langage C ? Fonctions systèmes ? Je suis perdu !
III-A. Domaine couvert par le langage C
III-B. Fonctions système
III-C. Bibliothèques tierces publiques
III-D. Bibliothèques tierces privées
IV. C, UNIX, POSIX ?
V. Production du code exécutable
VI. pile, tas ? C'est quoi ?
VII. Le mode plein écran
VII-A. Installation de ansi.sys sous Windows XP
I. C'est quoi l'algorithmique ?
C'est l'art de traduire un comportement en phrases simples
et claires.
Surveiller la température. Si elle dépasse la consigne,
actionner une alarme.
Ces phrases sont ensuite traduites en 'pseudo-code' qui
est une sorte de langage de description des comportements
(ressemble au Pascal) à base d'actions et de structures de code comme
IF-ELSE-ENDIF, SELECT-CASE,
REPEAT-UNTIL, WHILE etc.
DO
temperature := read_temperature ()
IF temperature > threshold
alarm (ON)
ENDIF
FOREVER
|
Ce pseudo-code est ensuite traduit facilement en langage
d'implémentation. (Par exemple en C)
{
for (;;)
{
int temperature = read_temperature ();
if (temperature > threshold)
{
alarm (ON);
}
}
}
|
II. Déclarations ? Définitions ?
Il y a beaucoup de confusions sur les termes définition et
déclaration en C. Voici un petit article qui
va s'efforcer de mettre les choses au point.
II-A. Déclaration
Une déclaration permet l'utilisation d'un objet ou d'une
fonction. Elle doit être préalable à l'utilisation.
Exemples avec un objet x de type int :
extern int x;
< ...>
{
x = 2 ;
}
|
ou
ou
Voici des exemples de déclarations de fonctions
int f ();
extern int g (void );
static int h ();
static int i (int a)
{
}
int j (char * b)
{
}
|
II-B. Définition
Une définition est l'endroit où l'objet ou la fonction
sont réellement définis. De l'espace mémoire est
alloué à l'objet, les instructions sont fournies à la fonction (entre des
{}). Notons que par conséquent,
une définition est aussi une déclaration implicite. Il convient donc
d'être prudent sur l'emploi
des termes. Voici des définitions d'objets :
int a;
static float b[12 ];
{
struct xxx c;
static long d;
}
|
ou de fonction
int f ()
{
}
int g (void )
{
}
|
La dernière forme est une définition avec déclaration
implicite sous forme de prototype
III. Langage C ? Fonctions systèmes ? Je suis perdu !
Sur un forum je pose une question sur le langage C et on
me répond "va voir sur un forum consacré à
ton système". M'enfin, je programme en C, c'est quoi ce cirque ?
III-A. Domaine couvert par le langage C
Le langage C, tel qu'il est défini par la norme, est un
ensemble de règles d'écriture (syntaxe, sémantique)
définissant les éléments du langage, et un ensemble de fonctions regroupées
sous le terme générique
de 'bibliothèque d'exécution du [langage] C'.
Les domaines couverts par la bibliothèque sont
-
Les flux d'entrée/sorties
-
Les traitements de chaines
-
Les conversions chaine/binaires
-
Les fonctions mathématiques
-
Les algorithmes génériques (tri, recherche)
-
La gestion du temps
-
(d'autres qui me reviendront plus tard...)
On constate donc qu'un programme C standard permet
d'entrer des données à partir de la ligne de commande
(paramètres de main()) ou d'un flux entrant (stdin, fichier en lecture), de
les traiter 'silencieusement',
ou avec une trace vers un flux sortant (stdout, stderr ou un fichier
en écriture) et de sortir
des données vers une un flux sortant selon le schéma bien connu.
+ - - - - - - - - + + - - - - - - - - - - - - + + - - - - - - - - +
| entrée | - - > | traitement | - - > | sortie |
+ - - - - - - - - + + - - - - - - - - - - - - + + - - - - - - - - +
|
Exemples typiques
-
compilateur
-
générateur de code
-
convertisseur wav -> mp3
-
etc.
Si on cherche d'autres domaines d'applications comme
-
Gestion de l'écran en mode texte
-
Lecture du clavier sans attente
-
Impression
-
Port série
-
Réseau
-
Ecran graphique
-
Programmation évènementielle
-
Programmation multitâches
-
Interface graphique
-
Souris
-
etc.
il va falloir utiliser des ressources externes au langage C. Bien que ces ressources disposent (entre
autres), d'une interface leur permettant d'être appelées par un programme écrit en C, elles
ne font pas partie du langage C.
On distingue principalement 3 types de ressources
-
Les fonctions fournies par le système
-
Les fonctions des bibliothèques publiques (gratuites, payante)
-
Les fonctions des bibliothèques privées (personnelles, entreprises)
III-B. Fonctions système
Rappelons qu'un système est un logiciel lancé par la machine au démarrage et qui prend en charge la gestion
des ressources matérielles, ainsi que la surveillance de différents évènements. D'autre part, il
fourni un certain nombre de fonctions utilisables dans les applications, ainsi que le moyen de
charger et lancer (exécuter) une ou des applications.
L'ensemble des interfaces des fonctions système utilisables pour développer des applications est décrit
dans un document appelé API (Application Programming Interface). Ce document précise pour chaque
fonction :
-
identificateur
-
paramètres
-
retour
-
comportement
Pour des raisons propres à chaque architecture, l'interface est souvent matérialisée par un 'TRAP' ou
une interruption logicielle que l'on ne peut appeler qu'en assembleur. Par exemple en sur un PC/x86,
l'interruption BIOS 'Vidéo':
MOV AH, 09h
MOV AL, character
MOV BH, 00h
MOV BL, attributes
MOV CX, 01h
INT 10h
|
ou avec des extensions de très bas niveau comme par exemple ceci en Borland C:
# if defined ( __BORLANDC__ )
# include <dos.h>
# else
# error Undefined for this platform
# endif
< ...>
void VIDEO_putch (int c, eCOU ct, eCOU cf)
{
# if defined ( __BORLANDC__ )
union REGS reg;
reg.h.al = (uchar) c;
reg.h.ah = 0x09 ;
reg.h.bh = 0 ;
reg.h.bl = (uchar) (ct | ((cf & ~ 0x08 ) < < 4 ));
reg.x.cx = 1 ;
int86 (0x10 , & reg, & reg);
# endif
}
|
Afin de faciliter l'appel à partir de différents langages de développement, chaque implémenteur de compilateur
(C, C++, Pascal, Ada etc.) ou d'interpréteur (BASIC, Python, Ruby etc.) fournit une interface dans
son langage. Les fonctions systèmes apparaissent donc comme une extension dudit langage.
Chaque système dispose de sa propre API. Mais certains systèmes offrent des API définies selon la norme
POSIX, ce qui tend à normaliser
au moins une partie des API.
III-C. Bibliothèques tierces publiques
Il est aussi possible d'utiliser des fonctions fournies par des bibliothèques publiques gratuites ou
payantes selon les besoins et les licences requises. Ces bibliothèques sont le plus souvent indépendantes
de la plateforme. On peut citer (interface C)
-
GTK+ (GUI)
-
SDL (Graphisme 2D simple)
-
Fmod (Multimédia)
-
MySQL (SGBD)
-
etc.
III-D. Bibliothèques tierces privées
Chaque développeur peut, pour lui-même, ou au sein de son entreprise, développer une bibliothèque de
fonctions 'métier' qui lui facilitent la réalisation d'applications spécialisées. Il est courant
que ces bibliothèques soient partagées dans l'entreprise.
Certaines de ces bibliothèques peuvent ensuite devenir publiques si elles peuvent intéresser d'autres
personnes et si la licence le permet.
IV. C, UNIX, POSIX ?
Le langage C n'a à voir ni avec UNIX ni avec POSIX.
UNIX est une norme de spécification de système (Actuellement UNIX 03) gérée par l'
Open
Group qui définit un système indépendamment de la machine sur lequel il tourne. Elle s'appuie,
entre autre, sur la spécification des fonctions systèmes définie par POSIX.1 sous l'égide de l'IEEE.
Cette norme (POSIX.1) comprend à la fois la description d'un certain nombre de fonctions systèmes, et
d'au moins deux types d'interfaces :
-
Le mode commande (shell) pour l'utilisateur de la machine.
-
Une API utile aux programmeurs d'applications.
L'API est décrite sous la forme d'interfaces de fonctions appelables directement en langage C (C99 pour
les dernières specs de POSIX.1). Les fonctions standards du C sont reprises telles quelles par POSIX.1.
NOTA : Ce sont ces nombreux emprunts au langage C qui ont créés la confusion entre langage C et POSIX
...
Cette API est implémentée par une bibliothèque (.a, .so, .lib, .dll, ...) et des fichiers d'entête (.h)
livrés avec les systèmes compatibles POSIX.1 (la plupart des unixoïdes, mais aussi certains Windows).
La spécification complète de POSIX.1 est disponible
ici
(s'inscrire, c'est gratuit et sans danger).
Les constructeurs de systèmes et de compilateurs s'efforcent de suivre tout ou partie de ces normes,
ce qui permet une portabilité importante dans des domaines qui ne sont pas couverts par la norme
du langage C comme
-
La gestion des répertoires
-
La gestion des processus (process)
-
La gestion des tâches (threads)
-
La gestion des réseaux (sockets)
-
etc.
V. Production du code exécutable
Il existe de nombreuses implémentations du langage C. Certaines sont des interpréteurs, mais la plupart
sont des compilateurs.
Compiler un programme consiste à vérifier le code source, puis à le traduire en langage machine de façon
à en faire un fichier exécutable qui pourra ensuite être exécuté par la machine.
Les détails de production du code dépendent de l'implémentation, c'est à dire de la machine, du système,
des outils utilisés etc. Cependant, il existe une procédure générale commune à toutes ces implémentations
:
-
Production de modules de code machine intermédiaires par compilation individuelle des codes sources.
Il manque les références externes.
-
Production du code machine exécutable par résolution des références externes (liens) entre les modules
intermédiaires, et l'éventuelle ajout de bibliothèques de fonctions selon les besoins.
Pour cela, on utilise successivement 2 outils :
-
Le compilateur (compiler), autant de fois que nécessaire, selon le nombre de fichiers sources
à traiter.
-
L'éditeur de lien (linker), une fois pour produire l'exécutable.
VI. pile, tas ? C'est quoi ?
Le langage C définit 3 zones de stockage pour les objets (aussi appellés variables)
-
La mémoire statique
-
La mémoire allouée
-
La mémoire automatique
1 - Les objets définis hors des fonctions et les objets définis avec le mot clé static sont placés en
mémoire statique. Leur durée de vie est celle de l'exécution du programme. Ils existent et sont
initialisés (à 0 par défaut) avant même le lancement de main().
2 - Les objets définis avec les fonctions malloc(), calloc() et realloc() sont placés en mémoire allouée
(appelée heap ou tas sur certaines implémentations). Leur durée de vie est contrôlée par le programme.
Ils existent dès que l'appel de *alloc() retourne une valeur différente de NULL et cessent d'exister
dès que free() est appelé avec la valeur retournée par *alloc().
3 - Les objets définis dans un bloc, sans qualificateur 'static', sont placés en mémoire automatique
(appelée stack ou pile sur certaines implémentations). Leur durée de vie est celle du bloc dans
lequel ils sont définis.
VII. Le mode plein écran
En C standard, la notion d'écran (et plus généralement de matériel) n'existe pas. Une application écrite
en C est censée tourner sur une machine abstraite dont les interfaces matérielles sont vues comme
des flux d'entrée ou de sortie. Ceci dans un souci de portabilité, qui est une des raisons d'être
du langage C.
Parmi ces flux, il en existe 3 qui sont ouverts par défaut :
-
stdin : entrée standard
-
stdout : sortie standard
-
stderr : sortie erreur
Une application écrite en C peut être recompilée pour une multitude de plateformes (qui diffèrent selon
le processeur, l'architectures, le système, etc.) pour lesquelles stdin, stdout et stderr seront
implémentés de manières différentes.
Sur un modem, par exemple, ces flux seront connectés à un port série permettant de brancher une console
par laquelle on pourra passer, par exemple, des commandes AT.
Le but est d'instaurer un dialogue 'interactif' dans lequel l'application montre qu'elle attend une commande
de l'opérateur à l'aide d'un 'prompt' ou 'invite de commande':
L'utilisateur peut alors passer une commande de numérotation
et le modem répond
il passe alors en mode transmission de données, et il signale qu'il n'attend plus de commandes par l'absence
de prompt.
De même, sur un PC sous Windows ou unixoide, il est possible d'ouvrir une console localement ou de se
brancher localement ou à distance sur la machine via une console (gestion, application, debug...).
L'application ne verra pas la différence et continuera à attendre ses commandes de stdin et à envoyer
ses réponses à stdout et/ou stderr.
L'avantage d'un tel système est qu'il exige très peu de la console, qui peut se réduire à un simple terminal
série, voire à une imprimante série s'il ne s 'agit que de traces sur stdout ou stderr (utile pour
mettre au point une application graphique, par exemple).
La gestion plein écran est une autre façon de concevoir la relation entre l'homme et la machine (IHM).
En effet, on peut reprocher à l'interface console 'interactive', un certain manque de convivialité
(largement compensé par le développement de langages 'scripts' extrêmement puissants), rendant les
applications difficiles d'accès à un public non informaticien (direction, comptables, secrétaires,
achats, commerciaux etc.)
C'est pour cela qu'il a été développé la notion d'interface 'plein écran' qui permet d'améliorer l'ergonomie.
-
Effacement de l'écran
-
Placement absolu du curseur
-
Contrôle de la couleur du texte et du fond
Malheureusement, il n'a jamais été prévu de norme internationale régissant cette gestion d'écran (probablement
parce que faisant trop partie du domaine applicatif, chaque constructeur voulant tirer parti des
performances de son matériel et de son logiciel).
Certaines pratiques et normes de fait se sont toutefois imposées.
-
Basées sur les ressources de la machine :
-
PC/MS-DOS : Borland et sa bibliothèque conio (Turbo Pascal, C) pour la console intégrée. Windows bénéficie
d'un portage réduit de conio pour MinGW (PDF).
-
Unixoides : curses et ncurses. (consoles locales)
-
Basées sur des ressources console
-
Commandes ANSI (VT-100)
-
Vidéotex (Minitel)
-
HTML (Browser)
Je recommande la bibliothèque
PDCurses qui est une
version portable et multi-plateforme de [n]curses et qui permet facilement de gérer les entrées/sorties
directes à la console, et ce soit d'une manière basique à-la-conio, ou d'une manière plus avancée.
Il existe de nombreux tutoriels sur le net.
Mention spéciale pour 'termcaps' qui est une bibliothèque multi-plateforme censée s'adapter à quasiment
tous les terminaux supportant des séquences d'échappement. Exemple d'implémentation :
vv_termcaps
VII-A. Installation de ansi.sys sous Windows XP
|
A ma connaissance, il n'y a pas de possibilité d'installer un interpréteur de séquences ANSI pour cmd.exe.
|
Copyright © 2009 Emmanuel Delahaye.
Aucune reproduction, même partielle, ne peut être faite
de ce site ni de l'ensemble de son contenu : textes, documents, images, etc.
sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à
trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.