Programmation Ada/FAQ/Le Langage Ada
École Nationale Supérieure des Télécommunications
Département Informatique et Réseaux
Copyright © 2001-2007 Samuel Tardieu et les différents auteurs des réponses.
Cet article est livré en l'état, sans garantie déclarée ni implicite.
Bien que tous les efforts aient été déployés pour s'assurer de la validité des informations contenues dans ce document, l'auteur ne pourra être tenu pour responsable d'erreurs, ou d'omissions, ni d'éventuels dommages résultant de leur utilisation.
Ce document peut être librement copié et distribué en respectant les conditions de la Licence de documentation libre GNU.
= ../Généralités/ =
=Le langage Ada=
Comment transformer un entier en chaîne de caractères ?
En Ada, les types scalaires tels que les entiers, les réels et les types énumérés disposent d'un attribut Image qui permet d'obtenir une chaîne de caractères à partir d'une valeur de ce type et un attribut Value qui permet d'effectuer l'opération inverse.
L'usage de ces deux attributs est illustré dans l'Exemple 1.
Exemple 1. Renvoyer une chaîne contenant un montant en Euros
function Euros (Montant : Natural) return String is
begin
 return Natural'Image (Montant) & "EUR";
end Euros;
Comment transformer une chaîne de caractères en entier ?
Comme indiqué dans la question précédente, les types scalaires disposent d'un attribut Value, comme illustré dans l'Exemple 2.
Exemple 2. Lire la valeur d'un entier
A : constant Integer := Integer'Value ("10"); -- A vaut 10
Comment obtenir le code ASCII d'un caractère ?
Dans ce cas également, des attributs sur le type codice_1 existent :
Pos, qui sert à obtenir la position d'une valeur dans le type énuméré qui le définit, et Val qui effectue l'opération inverse.
L'Exemple 3 illustre l'utilisation de ces attributs.
Exemple 3. Obtenir le code ASCII d'un caractère
X : constant Integer := Character'Pos ('A'); -- X vaut 65
Y : constant Character := Character'Val (66); -- Y vaut 'B'
Est-il possible de définir un nouvel attribut (par exemple Somme, qui ferait la somme de plusieurs valeurs d'un type donné) ?
Non.
Seuls certains attributs existants peuvent être modifiés, mais en aucun cas un nouvel attribut ne peut être ajouté par l'utilisateur.
Comment obtenir le minimum (resp. maximum) de deux entiers ?
Les types numériques disposent d'un attribut Min (resp. Max) qui permet d'obtenir le minimum (resp. le maximum) de deux nombres de ce type.
L'Exemple 4 présente l'utilisation de ces attributs.
Exemple 4. Maximum de deux entiers
-- La fonction suivante retourne le double du maximum de deux entiers
function Double_Maximum (X, Y : Integer) return Integer is
begin
 return 2 * Integer'Max (X, Y);
end Double_Maximum;
Comment saisir une chaîne de caractères de taille variable ?
On peut utiliser Ada.Text_IO.Get_Line, qui prend deux paramètres en lecture/écriture.
Dans la version à deux paramètres, le premier est la chaîne dans laquelle lire les caractères et le second contient, à la sortie de la procédure, la position du dernier caractère dans le tampon de saisie, comme illustré dans l'Exemple 5.
La variable contenant cette position doit pouvoir contenir toutes les valeurs possibles, y compris celle désignant la chaîne vide.
Exemple 5. Lire une chaîne de taille variable
with Ada.Text_IO;
declare
 Buffer : String (1 .. 30); -- Tampon de 30 caractères
 Last : Natural;
begin
 Ada.Text_IO.Get_Line (Buffer, Last); -- Lit au plus 30 caractères
 if Last = 0 then
 Ada.Text_IO.Put_Line ("Vous n'avez entré aucun caractère");
 else
 Ada.Text_IO.Put_Line ("Ok, vous avez entré: " & Buffer (1 .. Last));
 end if;
end;
Pourquoi après un Ada.Text_IO.Get_Line le curseur ne se trouve-t-il pas en début de la ligne suivante ?
Si l'utilisateur rentre le nombre de caractères maximum fixé par le second paramètre de codice_2, la saisie s'arrêtera à ce moment là et aucun retour chariot ne sera pris en compte.
Une solution consiste à utiliser codice_3 avant une nouvelle entrée ou une nouvelle sortie.
Pourquoi Get ou Get_Line après un Get n'attendent rien et se comportent comme si j'avais tapé uniquement sur la touche entrée ?
La version de codice_4 permettant de saisir un type scalaire ne consomme que les caractères nécessaires.
Le caractère entrée correspondant au retour chariot est alors conservé dans le tampon de saisie.
L'utilisation de codice_4 ou codice_2 consommera alors ce caractère.
Notons que ce comportement, qui peut paraître au premier abord peu intuitif, introduit une symétrie entre codice_7 et codice_4, entre Put_Line et codice_2 et entre codice_10 et codice_11.
Quel est le caractère de fin de chaîne ?
Aucun.
Pour le langage C, une chaîne est uniquement une suite de caractères terminée par un caractère NUL (0).
Ada dispose pour sa part d'un véritable type String qui permet de représenter une chaîne de caractères à l'aide de sa longueur, et non pas à l'aide d'un caractère arbitraire.
Comment récupérer la ligne de commande ?
En utilisant le paquetage standard codice_12, qui offre notamment les fonctions codice_13 et codice_14.
Comment effacer l'écran ?
Cette question est trop imprécise : on n'utilisera pas la même méthode pour effacer l'écran sous DOS, sous Windows ou sous X-Window.
Il n'y a pas de méthode normalisée en Ada.
Comment tracer un trait ?
Même réponse que dans la question ci-dessus : la question n'est pas assez précise.
Comment effacer l'écran sous Windows ?
Il est possible d'utiliser le paquetage codice_15.
Comment libérer un pointeur ?
Il faut instancier la procédure générique codice_16.
L'instance fournit une procédure permettant de libérer un pointeur du type voulu, comme illustré dans l'Exemple 6.
Exemple 6. Désallouer une zone mémoire
with Ada.Unchecked_Deallocation;
package Foo is
 type Tab is array (Natural range <>) of Integer;
 type Tab_Access is access Tab;
 procedure Free is
 new Ada.Unchecked_Deallocation (Tab, Tab_Access);
 -- Si on a une variable T de type Tab_Access, on
 -- peut maintenant invoquer Free (T).
 end Free;
end Foo;
Doit-on vraiment instancier Ada.Unchecked_Deallocation pour chaque type ?
Oui.
Cependant, en utilisant la programmation « class-wide », il est possible de créer un déallocateur pour l'ensemble de la hiérarchie, avec une seule instanciation.
Existe-t-il un ramasse-miettes pour Ada ?
Très peu d'implémentations proposent un ramasse-miettes[1].
En règle générale, seuls les compilateurs ciblant la machine virtuelle Java en fournissent un.
Si un compilateur Ada cible la machine virtuelle .NET, il est probable qu'il utilisera le ramasse-miettes sous-jacent.
Cependant, le paquetage codice_17 permet de contrôler la déallocation profonde d'un objet qui sort du contexte dans lequel il est défini.
Comment créer une chaîne de caractères de taille inconnue à priori ?
Il faut initialiser la chaîne de caractères au moment de sa création, comme dans l'Exemple 7.
Exemple 7. Création de chaîne
S : String := "ma chaîne" -- S est de taille 9 et de contenu modifiable
T : String := F (X, Y); -- T aura la taille requise
U : constant String := "bonjour"; -- U est de taille 7 et de contenu non modifiable
Est-il possible de gérer les chaînes de caractères comme en C ?
Oui, c'est possible, en utilisant un type «pointeur sur chaîne de caractères», mais il existe la plupart du temps de meilleures solutions.
Est-il possible de gérer des chaînes de caractères de taille variable ?
Il existe un type standard codice_18 qui permet de créer des chaînes de caractères de taille variable.
Lorsque l'on connaît la taille maximale de la chaîne, le type standard codice_19 est généralement plus efficace.
Existe-t-il un équivalent en Ada de la fonction realloc() du C, qui permet de changer la taille allouée pour une zone mémoire ?
Non.
Toutefois, la possibilité d'utiliser une valeur initiale pour la primitive codice_20 permet de remplacer facilement cette fonction, comme illustré dans l'Exemple 8.
Exemple 8. Ajouter un caractère à une chaîne
with Ada.Unchecked_Deallocation;
type String_Access is access String;
procedure Free is new Ada.Unchecked_Deallocation (String, String_Access);
S, Old_S : String_Access;
Old_S := S;
S := new String'(S.all & " ");
Free (Old_S);
Que signifie le pragma Pure ?
Cette directive de compilation signifie que le paquetage auquel elle s'applique ne contient que des sous-programmes sans effet de bord, et déterministes.
En gros, les sorties ne dépendent que des entrées, et pas d'un quelconque état interne ou externe.
Comment convertir une chaîne de caractères en minuscules ?
Il faut utiliser la fonction codice_21 du paquetage codice_22.
Comment faire des opérations bit à bit ?
En Ada, les opérations bit à bit se font sur les types modulaires.
Les opérations codice_23, codice_24, codice_25 et codice_26 sont définies.
Le paquetage standard codice_27 définit des opérations de décalage supplémentaires.
Est-il possible d'obtenir des tranches de tableaux multi-dimensionnels ?
Non.
Comment attendre un temps donné ?
Il faut utiliser l'instruction codice_28 suivie d'un nombre de secondes en virgule fixe (type codice_29), comme illustré dans l'Exemple 9.
Exemple 9. Attendre deux secondes et demie
delay 2.5; -- Attend 2,5 secondes
Comment effectuer un tirage aléatoire ?
Ada propose plusieurs paquetages de gestion de nombres aléatoires.
Le plus simple, pour obtenir un élément parmi une énumération, est d'utiliser codice_30, un paquetage générique qu'il faut instancier avec un type représentant l'ensemble tel qu'illustré dans l'Exemple 10.
Pour un tirage aléatoire sur un nombre réel, il est possible d'utiliser le paquetage codice_31 qui permet d'obtenir une variable aléatoire uniforme entre 0 et 1.
Exemple 10. Tirer un nombre entre 0 et 36
with Ada.Numerics.Discrete_Random;
with Ada.Text_IO;
procedure Roulette is
 type Numero is range 0 .. 36;
 package La_Roulette is new Ada.Numerics.Discrete_Random (Numero);
 use La_Roulette; -- Rend Generator, Reset et Random visibles
 A : Numero;
 G : Generator;
begin
 Reset (G); -- Initialise le générateur (à faire une seule fois)
 A := Random (G); -- Tire un nombre au hasard entre 0 et 36
 Ada.Text_IO.Put_Line ("Le numéro est: " & Numero'Image (A));
end Roulette;
Où se trouvent les fonctions mathématiques ?
Les fonctions mathématiques élémentaires (comme la racine carrée) se trouvent dans le paquetage codice_32.
Les fonctions présentes dans ce paquetage permettent de travailler sur le type de base codice_33.
Pour utiliser de telles fonctions avec un autre type de nombres flottants, il faut utiliser une instanciation du paquetage générique codice_34.
Comment augmenter la taille de la pile d'une tâche ?
La directive de compilation codice_35 permet de donner la taille, en unités de stockage (octets en pratique), de la pile d'une tâche ou d'un type de tâche, comme illustré dans l'Exemple 11.
Exemple 11. Choisir la taille de la pile d'une tâche
task T is
 pragma Storage_Size (300_000); -- 300 kilo-octets pour la pile
end T;
task body T is
end T;
Comment écrire un paquetage générique prenant, en paramètre, une classe dérivée d'une classe donnée ?
L'exemple 12 montre un paquetage générique prenant en paramètre une classe dérivée d'une autre classe, appelée ici Classe_Abstraite.
Exemple 12. Paquetage générique et classe dérivée
with Abstrait;
generic
 type Classe_Concrete is new Abstrait.Classe_Abstraite with private;
package Generic_Test is
end Generic_Test;
= ../Bibliothèques/ =
= Compilateurs et outils =
= Sociétés et fournisseurs liés à Ada =