Formation ADA pour le temps réel et les systèmes distribués, tutoriel & guide de travaux pratiques en pdf.
La gestion du bas niveau
Ada étant un langage également destiné à la programmation des systèmes, il était nécessaire de fournir des interfaces de bas niveau. Il est ainsi possible de forcer la représentation physique des structures abstraites, de spécifier des traitements d’interruptions physiques, d’inhiber des vérifications de type, et même d’inclure du code machine. Toutefois, des précautions ont été prises pour que même ce genre de manipulations ne puissent se faire sans un minimum de précaution.
IV.1 Clauses de représentation.
Une possibilité très intéressante est la possibilité de spécifier au bit près la représentation des types de données. Normalement, la représentation interne est choisie par le compilateur, et le langage garantit la totale indépendance de l’utilisation des types vis à vis de leur représentation. Cependant, il peut être nécessaire d’imposer une représentation, notamment lors d’interfaçages avec le matériel ou avec des sous programmes écrits dans d’autres langages. On peut alors donner au programmeur une vision de haut niveau, tout en imposant la représentation de bas niveau. On peut ainsi décrire une cellule de mémoire écran d’IBM-PC:
type T_COULEUR is (Noir, Bleu, Vert, Cyan, Rouge, Magenta, Marron, Gris, Gris_sombre, Bleu_clair, Vert_clair, Cyan_clair, Rouge_clair, Magenta_clair, Jaune, Blanc); subtype T_COULEUR_FOND is T_COULEUR range Noir..Gris;
— Représentation des énumératifs: for T_COULEUR use (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
type T_CLIGNOTEMENT is (Fixe, Clignotant); for T_CLIGNOTEMENT use (0, 1)
type T_ATTRIBUT is record Clignotement : T_CLIGNOTEMENT; Fond : T_COULEUR_FOND; Devant : T_COULEUR; end record
RTS’95 – J-P. Rosen, Adalog
— Représentation du type article: at <mot> — range <bits> for T_ATTRIBUT use record Clignotement at 0 range 0..0; Fond at 0 range 1..3; Devant at 0 range 4..7; end record;
Si l’on veut changer la valeur du bit « Clignotement » d’un attribut, on écrira simplement:
A.Clignotement := Fixe;
ce qui aura effectivement pour effet de changer la valeur du bit considéré. On voit qu’ainsi, il n’est plus jamais besoin de calculer des masques, décalages, etc. pour intervenir à bas niveau. En cas de modification de la représentation interne des données, aucune modification du code n’est nécessaire.
On voit que les règles du langage ne sont nullement changées par la présence de clauses de représentation, ce qui constitue un outil très puissant. Supposons que nous ayons besoin, par exemple lors de l’écriture d’une interface, de deux représentations physiques différentes d’un même type de données. Il suffit de faire un type dérivé muni de clauses différentes de celles d’origine. Les types dérivés étant convertibles entre eux, le changement de représentation sera pris en charge par le compilateur, comme dans l’exemple suivant:
type Format_1 is … for Format_1 use … — Représentation de Format_1
type Format_2 is new Format_1; for Format_2 use… — Représentation de Format_2
V1 : Format_1; V2 : Format_2; begin … V1 := Format_1(V2); — Conversion prise en charge par le compilateur V2 := Format_2(V1); — Conversion prise en charge par le compilateur
Ces conversions sont des conversions de haut niveau, respectant la sémantique des types. Il est parfois nécessaire d’effectuer des conversions plus directes (type cast), notamment lorsqu’une même donnée doit être vue selon deux niveaux d’abstraction différents. Par exemple, des caractères sont des entités propres, qui ne sont pas considérées comme des valeurs numériques. On ne peut donc additionner des caractères, ce qui n’aurait aucun sens… sauf si l’on veut calculer un CRC. On peut alors forcer une vue d’un caractère sous forme numérique grâce à l’instantiation de la fonction UNCHECKED_CONVERSION:
type Octet is mod 256; — type modulaire for Octet’Size use 8; — représenté sur 8 bits
function Char_to_Octet is new Unchecked_Conversion(Character, Octet);
CRC : Octet; C : Character; begin … CRC := CRC * 2 + Char__to_Octet(C);
La sécurité des types n’est pas mise en cause, car les règles du langage imposent dans ce cas de mettre en tête de module une clause « with UNCHECKED_CONVERSION; », dont la présence est tracée par le compilateur. Les zônes de code effectuant ce genre d’opérations, potentiellement dangereuses ou non portables, sont donc instantanément identifiables.