IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

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);
      }
   }
}
Un article plus complet.


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

int x;

<...>
{
   x = 2;
}
ou

{
   int x;
<...>
   x = 2;
}
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

<...>

/* ---------------------------------------------------------------------
   VIDEO_putch()
   ---------------------------------------------------------------------
   ecriture d'un caractere a la position courante du curseur avec
   la couleur specifiee
   ---------------------------------------------------------------------
   E : caractere (0-255)
   E : couleur texte
   E : couleur fond
   S :
   --------------------------------------------------------------------- */
void VIDEO_putch (int c, eCOU ct, eCOU cf)
{
#if defined (__BORLANDC__)
   union REGS reg;

   /* caractere a écrire */
   reg.h.al = (uchar) c;

   /* putch avec attribut */
   reg.h.ah = 0x09;

   /* page 0 */
   reg.h.bh = 0;

   /* attributs 08h : clignotement */
   reg.h.bl = (uchar) (ct | ((cf & ~0x08) << 4));

   /* pas de repetitions */
   reg.x.cx = 1;

   /* Bios Video */
   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':

modem> _
L'utilisateur peut alors passer une commande de numérotation

modem> ATD0123456789
_
et le modem répond

CONNECTED AT 9600 BAUDS
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

warning A ma connaissance, il n'y a pas de possibilité d'installer un interpréteur de séquences ANSI pour cmd.exe.
 

Valid XHTML 1.1!Valid CSS!

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.