Logo

Marco Cantù
L'essentiel sur Pascal

Traduit de l'anglais par Iannis Papageorgiadis ipapag@village.uunet.be

Chapitre 3 
Types, variables et constantes

Le langage Pascal était, à l'origine, basé sur quelques notions simples devenues très courantes dans les langages de programmation. La première notion est celle de type de données. Le type détermine les valeurs que peut avoir une variable et les opérations que l'on peut effectuer sur elle. Le concept de type est plus fort en Pascal qu'en C, où les types arithmétiques sont souvent interchangeables, et plus fort que dans les versions initiales du BASIC où un tel concept n'existait pas.

Les variables

Pascal exige que toutes les variables soient déclarées avant d'être utilisées. Chaque fois que l'on déclare une variable, on doit spécifier un type de données. Voici quelques déclarations de variables :
var

  Valeur: Integer;

  EstCorrect: Boolean;

  A, B: Char;
Le mot réservé var peut être utilisé à plusieurs endroits du code, par exemple au début du code d'une fonction ou d'une procédure, pour déclarer des variables locales à la routine, ou à l'intérieur d'une unité pour déclarer des variables globales. Après le mot var arrive la liste des noms de variables, suivie du caractère deux points et du nom du type de données. Vous pouvez écrire plusieurs noms sur une seule ligne comme dans la dernière instruction ci-dessus.

Une fois que l'on a défini une variable d'un type donné, on ne peut effectuer sur elle que les opérations permises par son type de données. Par exemple, on peut utiliser une valeur booléenne dans un test et une valeur entière dans une expression numérique. On ne peut pas mélanger booléens et entiers (comme on peut le faire dans le langage C).

En utilisant des assignations simples, nous pouvons écrire le code suivant :

Valeur := 10;
EstCorrect := True;
Mais l'instruction suivante n'est pas correcte, parce que les deux variables sont de types différents :
Valeur := EstCorrect; // erreur
Si vous essayez de compiler ce code, Delphi aboutit à une erreur de compilation avec la description : Types incompatibles: 'Boolean' et 'Integer'.  De telles erreurs sont habituellement des erreurs de programmation parce que assigner la valeur True ou la valeur False à une variable de type entier n'a aucun sens. Il ne faut pas blâmer Delphi pour ces erreurs. Il vous avertit simplement qu'il y a quelque chose d'incorrect dans le code.

Bien sûr, il est souvent possible de convertir la valeur d'une variable d'un type à un autre. Dans certains cas, cette conversion est automatique, mais habituellement vous devez faire appel à une fonction spécifique qui change la représentation interne de la donnée.

En Delphi, on peut assigner une valeur initiale à une variable globale lors de sa déclaration. Par exemple, on peut écrire :

var

  Valeur: Integer = 10;

  Correct: Boolean = True;
Cette technique d'initialisation fonctionne uniquement pour les variables globales et non pas pour les variables déclarées à l'intérieur de l'étendue d'une procédure ou d'une méthode.

Les constantes

Pascal permet aussi la déclaration de constantes pour nommer des valeurs qui ne changent pas pendant l'exécution du programme. Lors de la déclaration d'une constante, on ne doit pas spécifier un type de données, mais lui affecter uniquement une valeur initiale. Le compilateur verra la valeur et utilisera automatiquement son propre type de données. Voici quelques exemples de déclaration :
const

  Mille = 1000;

  Pi = 3.14;

  AuthorName = 'Marco Cantù';
Delphi détermine le type de données de la constante en fonction de sa valeur. Dans l'exemple ci-dessus, la constante Mille est considérée comme étant de type SmallInt, le plus petit type entier qu'il possède. Si vous souhaitez dire à Delphi d'utiliser un type spécifique, vous pouvez simplement ajouter dans la déclaration le nom du type, comme dans :
const

  Mille: Integer = 1000;
Lorsque on déclare une constante, le compilateur peut choisir d'allouer un emplacement mémoire à la constante et y placer sa valeur, ou dupliquer la valeur actuelle chaque fois que la constante est utilisée. Cette seconde approche est utilisée particulièrement pour les constantes simples.
 
Remarque : La version 16 bits de Delphi vous permet de changer la valeur d'une constante typée pendant l'exécution comme s'il s'agissait d'une variable. La version 32 bits le permet aussi pour la compatibilité ascendante si vous utilisez la directive de compilation $J, ou si vous utilisez la boîte à cocher Constantes typées affectables de la page Compilateur de la boîte de dialogue Options du menu Projet. Bien qu'il s'agisse d'une option par défaut, il est vivement conseillé de ne pas utiliser ce truc en tant que technique de programmation générale. Dans un tel cas, déclarez simplement une variable.

Les constantes chaîne de ressource

Lorsque vous définissez une constante chaîne, au lieu d'écrire:
const

  AuthorName = 'Marco Cantù';
à partir de Delphi 3 vous pouvez écrire
resourcestring

  AuthorName = 'Marco Cantù';
Dans les deux cas vous êtes en train de définir une constante; c'est-à-dire une valeur qui ne changera pas pendant l'exécution du programme. La différence réside uniquement dans l'implémentation. Une constante chaîne définie avec la directive resourcestring est stockée dans les ressources du programme dans une table de chaînes.

Pour illustrer cette possibilité, voyez l'exemple ResStr, qui possède un bouton avec le code suivant:

resourcestring

  AuthorName = 'Marco Cantù';

  BookName = 'Essential Pascal';



procedure TForm1.Button1Click(Sender: TObject);

begin

  ShowMessage (BookName + #13 + AuthorName);

end;
L'affichage des deux chaînes apparaît sur des lignes séparées vu que que les chaînes sont séparées par le caractère retour chariot (indiqué par sa valeur numérique dans la constante numérique #13).

Ce qu'il y a d'intéressant dans ce programme, c'est que si vous l'examinez avec un explorateur de ressources (il y en a un de disponible parmi les exemples compris dans Delphi), vous verrez les nouvelles chaînes parmi les ressources. Ceci signifie que les chaînes ne font pas partie du code compilé mais qu'elles sont stockées dans une zone séparée du fichier exécutable (du fichier EXE).
 

Remarque : En bref, l'avantage des ressources consiste en la gestion de la mémoire effectuée par Windows et la possibilité de transposer un programme (traduction des chaînes dans une autre langue) sans devoir modifier son code source.

Les types de données

En Pascal, il y a plusieurs types de données prédéfinis, lesquels peuvent être divisés en trois groupes : les types ordinaux, les types réels et les chaînes. Les sections suivantes examineront les types ordinaux et les types réels, tandis que les chaînes seront traitées plus loin dans ce chapitre. Dans cette section nous introduirons également quelques types définis par les bibliothèques Delphi (non prédéfinis par le compilateur), qui peuvent être considérés comme types prédéfinis.

Delphi inclut également un type de données non typé, appelé variant (cfr. Chapitre 10). Assez curieusement, un variant est un type sans contrôle de type propre. Il a été introduit en Delphi 2 pour la gestion des objets OLE Automation.

Les types ordinaux

Les types ordinaux sont basés sur le concept d'ordre ou de séquence. Non seulement on peut comparer deux valeurs pour trouver la plus grande, mais on peut également demander la valeur suivant ou précédant une valeur donnée, ou calculer la plus grande ou la plus petite des valeurs possibles.

Les trois types ordinaux les plus importants sont Integer, Boolean et Char (caractère). Cependant, il existe un certain nombre d'autres types apparentés qui ont la même signification mais une représentation interne et un intervalle de valeurs différents. La table ci-dessous donne la liste des types ordinaux de données pour la représentation des nombres.

Table 3.1 : Types de données ordinaux pour les nombres
 
Taille Signé 
Intervalle
Non signé 
Intervalle
8 bits ShortInt 
-128 .. 127
Byte 
0 .. 255
16 bits SmallInt 
-32768 .. 32767
Word 
0 .. 65535
32 bits LongInt 
-2.147.483.648 .. 2.147.483.647
LongWord (depuis Delphi 4) 
0 .. 4.294.967.295
64 bits Int64
16/32 bits Integer Cardinal
Comme on le remarque, ces types correspondent à des représentations différentes des nombres, dépendant du nombre de bits utilisés pour exprimer la valeur, et de la présence ou l'absence d'un bit de signe. Les valeurs signées peuvent être positives ou négatives, mais elles ont un intervalle de valeurs plus réduit, parce qu'elles disposent d'un bit en moins pour la valeur même. Vous pouvez vous référer à l'exemple Range, exposé dans la section suivante, pour l'intervalle courant de chaque type.

Le dernier groupe (noté 16/32) indique les valeurs ayant une représentation différente dans les versions 16 et 32 bits de Delphi. Integer et Cardinal sont fréquemment utilisés car ils correspondent à la représentation des nombres originelle dans le CPU.

Les types entiers de Delphi 4

Dans Delphi 3, les nombres non signés sur 32 bits désignés par le type Cardinal étaient en réalité des valeurs 31 bits s'étendant jusqu'à 2 mégabytes. Delphi 4 a introduit un nouveau type numérique non signé, LongWord, qui utilise une valeur réellement 32 bits allant jusqu'à 4 mégabytes. Le type cardinal est maintenant un alias du nouveau type LongWord. Le LongWord, comme signalé ci-dessus, permet à une donnée de plus de 2 MB d'être adressée par un nombre non signé. De plus, il correspond à la représentation native des nombres dans le CPU.

Un autre type nouveau introduit par Delphi 4 est le type Int64, qui représente des entiers jusqu'à 18 chiffres. Ce nouveau type est entièrement supporté par quelques routines de type ordinal (comme High et Low), de type numérique (comme Inc et Dec), ainsi que par quelques routines de conversion de chaînes (comme IntToStr). Pour la conversion opposée, d'un string à un nombre, il existe deux nouvelles fonctions spécifiques : StrToInt64 et StrToInt64Def .

Les Booléens

Des valeurs booléennes autres que le type Boolean sont souvent utilisées. Quelques valeurs booléennes avec une représentation spécifique sont exigées par les fonctions API Windows. Il s'agit des types ByteBool, WordBool, et LongBool.
 
En Delphi 3, pour la compatibilité avec Visual Basic et OLE Automation, les types de données ByteBool, WordBool, et LongBool ont été modifiés pour représenter la valeur True par -1, tandis que la valeur False est encore 0. Le type de données Boolean reste inchangé (True est 1, False est 0). Si vous avez utilisé des transtypages explicites dans votre code Delphi 2, le fait de transporter le code en Delphi 3 pourrait provoquer des erreurs.

Les caractères

Enfin, il existe deux représentations différentes pour les caractères: ANSIChar et WideChar. Le premier type représente les caractères 8 bits, correspondant à l'ensemble traditionnel de caractères ANSI utilisés par Windows; le second représente les caractères 16 bits, correspondant aux nouveaux caractères Unicode supportés par Windows NT et de façon partielle seulement par Windows 95 et 98. La plupart du temps on utilisera simplement le type Char, qui en Delphi 3 correspond au type ANSIChar. On se rappellera quand même que les 256 premiers caractères Unicode correspondent exactement aux caractères ANSI.

Les constantes caractère peuvent être représentées par leur notation symbolique, par exemple 'k', ou par une notation numérique, par exemple #78. Pour exprimer ce dernier cas, on peut également utiliser la fonction Chr, comme dans Chr(78).

Il est généralement préférable d'utiliser la notation symbolique lorsque'on indique des lettres, des chiffres, ou des symboles. Par contre lorsqu'on se réfère à des caractères spéciaux, on utilisera généralement la notation numérique. La liste ci-dessous comprend quelques caractères spéciaux parmi les plus souvent utilisés:

L'exemple Range

Pour donner une idée des différents intervalles de quelques types ordinaux, voici un petit programme Delphi nommé Range. Quelques résultats sont visibles à la figure 3.1.

FIGURE 3.1: L'exemple Range affiche des informations à propos des types de données ordinaux (ici des entiers).

Le programme Range est basé sur une simple fiche, qui comporte six boutons (nommés chacun en fonction d'un type de données ordinal) et quelques libellés (Labels), comme on le voit à la figure 3.1. Quelques libellés sont utilisés pour contenir du texte statique, d'autres pour afficher l'information à propos du type correspondant à chaque pression sur un bouton.

Chaque fois que vous cliquez sur un des boutons de droite, le programme met à jour les libellés. Les divers libellés indiquent le type de données, le nombre de bytes utilisés, ainsi que les valeurs minimum et maximum que le type de données peut stocker. Chaque bouton possède sa propre méthode réponse à l'événement OnClick puisque le code utilisé pour calculer les trois valeurs est légèrement différent d'un bouton à l'autre. Voici, par exemple, le code source de l'événement OnClick pour le bouton Integer (BtnInteger):

procedure TFormRange.BtnIntegerClick(Sender: TObject);

begin

  LabelType.Caption := 'Integer';

  LabelSize.Caption := IntToStr (SizeOf (Integer));

  LabelMax.Caption := IntToStr (High (Integer));

  LabelMin.Caption := IntToStr (Low (Integer));

end;
Si vous avez un peu d'expérience de programmation en Delphi, vous pouvez examiner le code source du programme pour comprendre comment il fonctionne. Pour les débutants, il suffit de noter l'utilisation des trois fonctions: SizeOf, High, et Low. Les résultats des deux dernières fonctions sont des ordinaux du même genre (ici des entiers), et le résultat de la fonction SizeOf est toujours un entier. La valeur retournée par chacune de ces fonctions est, pour commencer, convertie en une chaîne à l'aide de la fonction IntToStr, et elle est ensuite copiée dans les titres des trois libellés.

Les méthodes associées aux autres boutons sont fort semblables à celle décrite ci-dessus. La seule différence réside dans le type de données passées par paramètre aux différentes fonctions. La figure 3.2 donne le résultat de l'exécution de ce même programme sous Windows 95 après sa re-compilation avec la version Delphi 16 bits. En comparant les figures 3.1 et 3.2 on peut voir la différence entre les types de données Integer en 16 bits et en 32 bits.

FIGURE 3.2 : Le résultat de la version 16 bits de l'exemple Range, montrant de nouveau l'information à propos des entiers.

La taille du type Integer varie en fonction du CPU et du système d'exploitation que vous utilisez. En Windows 16 bits, une variable Integer occupe deux octets (bytes). En Windows 32 bits, un Integer occupe quatre bytes. C'est la raison pour laquelle, lorsque vous recompilez l'exemple Range, vous obtenez un affichage différent.

Les deux représentations différentes du type Integer ne posent pas de problème aussi longtemps que votre programme ne fait pas de suppositions à propos de la taille des entiers. S'il vous arrive de sauver un Integer dans un fichier utilisant une version et de le rappeler avec une autre, vous aurez quelques problèmes. Dans un tel cas, il faut choisir un type de données indépendant de la plate-forme (comme LongInt ou SmallInt). Pour les calculs mathématiques ou pour du code générique il vaut mieux se baser sur la représentation standard pour la plate-forme spécifique -- c'est -à - dire utiliser le type Integer -- parce que le CPU le préfère. Le type Integer devrait être votre premier choix lors de la manipulation des nombres entiers. N'utilisez une représentation différente que lorsqu'il y a une raison impérieuse de le faire.

Les routines des types ordinaux

Il existe quelques routines système (routines définies dans le langage Pascal et dans l'unité system de Delphi) qui travaillent sur des types ordinaux. Ils se trouvent dans la table 3.1. Les programmeurs C++  remarqueront que les deux versions de la procédure Inc, avec un ou deux paramètres, correspondent aux opérateurs ++  et += (les mêmes qui sont utilisés par la procédure Dec).

Table 3.2 : Routines système pour les types ordinaux
 
Routine  But
Dec Décrémente la variable passée par paramètre de un ou de la valeur du deuxième paramètre facultatif.
Inc Incrémente la variable passée par paramètre de un ou de la valeur spécifiée.
Odd Retourne True si l'argument est un nombre impair.
Pred Retourne la valeur précédant dans l'ordre la valeur de l'argument et déterminée par le type de données : la valeur précédente.
Succ Retourne la valeur suivante de l'argument : la valeur suivante.
Ord Retourne un nombre indiquant l'ordre de l'argument dans l'ensemble des valeurs du type de données.
Low Retourne la plus petite valeur dans l'intervalle du type ordinal passé par paramètre.
High Retourne la plus grande valeur dans l'intervalle du type de données ordinal.
Remarquez que quelques-unes de ces routines, lorsqu'elles s'appliquent à des constantes, sont automatiquement évaluées par le compilateur et remplacées par leur valeur. Par exemple, si vous appelez High(X) où X est un entier, le compilateur peut simplement remplacer l'expression par la plus haute valeur possible du type Integer.

Les types réels

Les types réels représentent des nombres à virgule flottante de formats divers. La plus petite taille stockée est donnée par les nombres Single, qui sont implémentés avec une valeur de 4 bytes. Il y a aussi  les nombres à virgule flottante Double, implémentés sur 8 bytes, et les nombres Extended, implémentés sur 10 bytes. Ils sont tous des types de données à virgule flottante avec des précisions différentes, qui correspondent aux représentations à virgule flottante standard IEEE, et qui sont directement supportés par le coprocesseur numérique du CPU, pour la vitesse maximum.

En Delphi 2 et Delphi 3, le type Real avait la même définition que dans la version 16 bits; il s'agissait d'un type 48-bits. Mais son utilisation a été désapprouvée par Borland, qui suggérait par contre d'utiliser les types Single, Double et Extended. Cette suggestion s'explique par le fait que l'ancien format 6-bytes n'est ni supporté par le CPU d' Intel ni listé parmi les types réels officiels de IEEE. Pour surmonter complètement le problème, Delphi 4 modifie la définition du type Real pour représenter un nombre en virgule flottante 8-bytes (64 bits) standard.

Outre l'avantage d'utiliser une définition standard, cette modification permet aux composants de publier des propriétés basées sur le type Real, ce que Delphi 3 ne permettait pas. Au nombre des inconvénients pourraient figurer les problèmes de compatibilité. Si nécessaire, on évitera la possibilité d'incompatibilité en s'en tenant aux définitions du type de Delphi 2 et Delphi 3; on utilisera pour cela  l'option de compilation suivante :

{$REALCOMPATIBILITY ON}
Il existe également deux types de données étranges : Comp décrit de très grands entiers utilisant 8 bytes (il peut contenir des nombres de 18 chiffres), et Currency (non disponible en Delphi 16 bits) qui indique une valeur à virgule fixe avec quatre décimales, et a la même représentation en 64 bits que le type Comp.

On ne peut pas construire un programme semblable à celui de l'exemple Range avec les types réels, parce qu'on ne peut pas utiliser les fonctions High, Low ou Ord avec des variables de type réel. Les types réels représentent (théoriquement) un ensemble infini de nombres; les types ordinaux représentent un ensemble fini de valeurs.

Remarque : Expliquons mieux la chose. Si vous avez l'entier 23, vous pouvez déterminer quelle est la valeur suivante. Les Integer sont finis (ils ont un intervalle déterminé ainsi qu'un ordre). Les nombres à virgule flottante sont infinis même à l'intérieur d'un petit intervalle, et ils n'ont pas d'ordre: en fait, combien de valeurs  y a-t-il entre 23 et 24 ? Et quel est le nombre qui suit 23,46 ? Est-ce 23,47,  23,461 ou 23,4601 ? Difficile à dire!

Pour cette raison, s'il est sensé de demander la position ordinale du caractère w dans l'intervalle du type de données Char, il est par contre insensé de poser la même question pour le nombre 7143,1562 dans l'intervalle d'un type de données à virgule flottante. Bien que vous puissiez évidemment savoir si un nombre réel est supérieur à un autre, il est insensé de demander le nombre de nombres qui précèdent un nombre donné (c'est le sens de la fonction Ord).

Les types réels jouent un rôle limité dans la partie interface utilisateur du code (du côté de Windows), mais ils sont entièrement supportés par Delphi, y compris le point de vue base de données. Le support du standard IEEE des types à virgule flottante fait que le langage Pascal Objet est parfaitement approprié pour la grande variété de programmes qui exigent des calculs numériques. Si vous vous intéressez à cet aspect, vous trouverez les fonctions arithmétiques prévues par Delphi dans l'unité système (pour plus de détails, voir l'aide Delphi).
 

Remarque : Delphi possède également une unité Math qui définit des routines mathématiques avancées, couvrant les fonctions trigonométriques (comme la fonction ArcCos), des routines financières (comme la fonction InterestPayment) et statistiques (comme la procédure MeanAndStdDev). Le nom de certaines de ces routines sonne étrangement, tel celui de la procédure  MomentSkewKurtosis (nous vous laisserons découvrir de quoi il s'agit).

Date et heure

Delphi utilise encore les types réels pour gérer les informations de date et d'heure. Plus précisément, Delphi définit un type de données spécifique TDateTime. Il s'agit d'un type à virgule flottante, puisque le type doit être suffisamment étendu pour stocker années, mois, jours, heures, minutes et secondes jusqu'à la milli-seconde dans une seule variable. Les dates sont stockées en tant que nombre de jours depuis le 30/12/1899 (avec des valeurs négatives indiquant les dates avant 1899) dans la partie entière de la valeur TDateTime. Le temps est stocké en fractions de jour dans la partie décimale de la valeur.

TDateTime n'est pas un type prédéfini compris par le compilateur, mais il est défini dans l'unité system comme suit :

type

  TDateTime = type Double;
Utiliser le type TDateTime est très aisé, parce que Delphi comprend une série de fonctions qui opèrent sur ce type. Vous trouverez une liste de ces fonctions dans la Table 3.2.

Table 3.3 : Routines système pour le type TDateTime
 
Routine Description 
Now Retourne la date et l'heure courantes dans une seule valeur.
Date Retourne uniquement la date courante.
Time Retourne uniquement l'heure courante.
DateTimeToStr Convertit une valeur date-heure en une chaîne, en utilisant le formatage par défaut; pour un meilleur contrôle de la conversion utilisez par contre la fonction FormatDateTime
DateTimeToString Copie la date et l'heure dans un tampon chaîne, avec le formatage par défaut.
DateToStr Convertit la partie date d'une valeur de type TDateTime en une chaîne.
TimeToStr Convertit la partie heure d'une valeur de type TDateTime en une chaîne.
FormatDateTime Formate une date et une heure en utilisant le format spécifique; vous pouvez spécifier les valeurs que vous souhaitez voir et le format utilisé, offrant un format chaîne complexe.
StrToDateTime Convertit une chaîne contenant une information date temps en une valeur TDateTime, soulevant une exception si la chaîne contient un format erroné.
StrToDate Convertit une chaîne avec une valeur date en un format TDateTime.
StrToTime Convertit une chaîne avec une valeur temps en un format TDateTime.
DayOfWeek Retourne le nombre correspondant au jour de la semaine de la valeur TDateTime passée en paramètre.
DecodeDate Récupère les valeurs année, mois et jour au départ d'une valeur date.
DecodeTime Sépare la valeur d' une valeur temps.
EncodeDate Renvoie les valeurs année, mois et jour dans une valeur TDateTime.
EncodeTime Renvoie les valeurs heure, minute, seconde et milli-seconde dans une valeur TDateTime.
Pour montrer comment utiliser ce type de données et ses routines, voici un petit exemple, baptisé TimeNow. La fiche principale de cet exemple contient un bouton et une boîte liste (ListBox). Au démarrage, le programme calcule et affiche automatiquement la date et l'heure courantes. A chaque pression du bouton, le programme indique le temps écoulé depuis le début du programme.

Voici le code relatif à l'événement OnCreate de la fiche:

procedure TFormTimeNow.FormCreate(Sender: TObject);

begin

  StartTime := Now;

  ListBox1.Items.Add (TimeToStr (StartTime));

  ListBox1.Items.Add (DateToStr (StartTime));

  ListBox1.Items.Add ('Pour le temps écoulé presser le bouton');

end;
La première instruction est un appel à la fonction Now qui retourne la date et heure courantes. Cette valeur est stockée dans la variable StartTime, déclarée en tant que variable globale comme suit :
var

  FormTimeNow: TFormTimeNow;

  StartTime: TDateTime;
Nous avons ajouté une deuxième déclaration, puisque la première a été prévue par Delphi. Par défaut elle est comme suit :
var

  Form1: TForm1;
En changeant le nom de la fiche, la déclaration est automatiquement mise à jour. Utiliser des variables globales n'est pas vraiment la meilleure approche. Il aurait été préférable d'utiliser un champ privé de la classe de la fiche, un sujet lié à la programmation orientée objet et traité dans Mastering Delphi 4.

Les trois instructions suivantes ajoutent trois éléments dans le composant ListBox de la fiche, avec le résultat que l'on peut voir dans la figure 3.3. La première ligne contient la partie temps de la valeur TDateTime convertie en une chaîne, la deuxième la partie date de cette même valeur. A la fin le code ajoute seulement un rappel.

FIGURE 3.3: Le résultat de l'exemple TimeNow au démarrage.

La troisième chaîne est remplacée par le programme lorsque l'utilisateur clique sur le bouton Temps écoulé :

procedure TFormTimeNow.ButtonElapsedClick(Sender: TObject);

var

  StopTime: TDateTime;

begin

  StopTime := Now;

  ListBox1.Items [2] :=  FormatDateTime ('hh:nn:ss',

    StopTime - StartTime);

end;
Ce code récupère le nouveau temps et calcule la différence à partir de la valeur du temps stocké lors du démarrage du programme. Puisque nous devons utiliser une valeur que nous avons calculée dans un gestionnaire d'événement différent, nous devons la stocker dans une variable globale. Il existe en fait de meilleures possibilités, basées sur les classes.
 
Remarque : Le code qui remplace la valeur courante dans la troisième chaîne utilise l'indice 2. La raison en est que les éléments d'une boîte liste (ListBox) sont numérotés à partir de zéro : le premier élément est l'élément numéro 0, le deuxième le numéro 1, et le troisième le numéro 2. Nous donnerons plus de détails lorsque nous traiterons les tableaux.
 
Outre l'appel à TimeToStr et DateToStr, vous pouvez utiliser la fonction plus performante FormatDateTime, comme nous l'avons fait dans la dernière méthode ci-dessus (pour les détails sur les paramètres de formatage, voir l'aide Delphi). Remarquez aussi que les valeurs temps et date sont transformées en chaînes en fonction des réglages internationaux de Windows. Delphi lit ces valeurs depuis le système, et les copie dans des constantes globales déclarées dans l'unité SysUtils.
En voici quelques-unes :
DateSeparator: Char;

ShortDateFormat: string;

LongDateFormat: string;

TimeSeparator: Char;

TimeAMString: string;

TimePMString: string;

ShortTimeFormat: string;

LongTimeFormat: string;

ShortMonthNames: array[1..12] of string;

LongMonthNames: array[1..12] of string;

ShortDayNames: array[1..7] of string;

LongDayNames: array[1..7] of string;
plus des constantes globales liées au formatage des nombres à virgule flottante et monétaires. Vous trouverez la liste complète dans le fichier d'aide de Delphi à la rubrique Variables de format monétaire et date/heure.
 
Remarque : Delphi comprend un composant DateTimePicker, qui fournit une voie sophistiquée pour introduire une date en la sélectionnant au départ d'un calendrier.

Les types Windows spécifiques

Les types de données prédéfinis que nous avons vus font partie du langage Pascal. Delphi comporte également d'autres types de données définis par Windows. Ces types de données ne font pas partie intégrante du langage, mais ils font partie des bibliothèques Windows. Les types Windows comprennent de nouveaux types par défaut (comme DWORD ou UINT), beaucoup d'enregistrements (ou structures), divers types pointeur, etc.

Parmi les types de données Windows, le type le plus plus important est représenté par les handles. Nous en discuterons au chapitre 9.

Conversions de type et transtypage

Comme nous l'avons vu, on ne peut pas assigner une variable à une autre d'un type différent. Dans le cas où vous devriez le faire, voici deux possibilités. La première est le transtypage, qui utilise une simple notation fonctionnelle, avec le nom du type de données destination :
var

  N: Integer;

  C: Char;

  B: Boolean;

begin

  N := Integer ('X');

  C := Char (N);

  B := Boolean (0);
Vous pouvez effectuer un transtypage entre types de données de même taille. Le transtypage entre types ordinaux ou entre types réels est souvent sans risque; mais vous pouvez également l'effectuer entre types pointeur (et aussi objets) tant que vous savez ce que vous êtes en train de faire.

Transtyper est, cependant, une pratique de programmation dangereuse parce qu'elle permet d'accéder à une valeur comme si elle représentait autre chose. Puisque les représentations internes des types de données ne s'accordent généralement pas, on risque d'aboutir à des erreurs difficiles à détecter.

La deuxième possibilité est d'utiliser une routine de conversion de type. Les routines pour les différents types de conversion sont résumées dans la table 3.3. Quelques-unes de ces routines s'appliquent à des types de données dont il sera question dans les sections suivantes. Remarquez que le tableau ne comprend pas de routines pour les types spéciaux (comme TDateTime ou variant) ou de routines spécialement destinées au formatage, comme les puissantes Format et FormatFloat.

Table 3.4: Routines système pour la conversion de type
 
Routine Description 
Chr Convertit un numéro ordinal en un caractère ANSI.
Ord Convertit une valeur de type ordinal en un nombre indiquant son ordre.
Round Convertit une valeur de type réel en une valeur de type Integer, en arrondissant sa valeur.
Trunc Convertit une valeur de type réel en une valeur de type Integer, en  tronquant sa valeur.
Int Retourne la partie entière de l'argument valeur à virgule flottante.
IntToStr Convertit un nombre en une chaîne.
IntToHex Convertit un nombre en une chaîne contenant la représentation hexadécimale du nombre.
StrToInt Convertit une chaîne en un nombre, soulevant une exception si la chaîne ne représente pas un entier valide.
StrToIntDef Convertit une chaîne en un nombre, utilisant une valeur par défaut si la chaîne n'est pas correcte.
Val Convertit une chaîne en un nombre (routine traditionnelle de Turbo Pascal, disponible pour la compatibilité).
Str Convertit un nombre en une chaîne, en utilisant des paramètres de formatage  (routine traditionnelle de Turbo Pascal, disponible pour la compatibilité).
StrPas Convertit une chaîne à zéro terminal en une chaîne style Pascal. Cette conversion est faite automatiquement pour AnsiString dans Delphi 32 bits. (Voir la section sur les chaînes plus loin dans ce chapitre).
StrPCopy Copie une chaîne style Pascal dans une chaîne à zéro terminal. Cette conversion est effectuée avec un simple typage PChar en DElphi 32 bits.
StrPLCopy Copie une partie d'une chaîne style Pascal dans une chaîne à zéro terminal.
FloatToDecimal Convertit une valeur virgule flottante en un enregistrement contenant sa représentation décimale (exposant, chiffres, signe).
FloatToStr Convertit une valeur virgule flottante en sa représentation chaîne en utilisant le format par défaut.
FloatToStrF Convertit une valeur virgule flottante en sa représentation chaîne en utilisant le format spécifié.
FloatToText Convertit une valeur virgule flottante dans une chaîne tampon en utilisant le format spécifié.
FloatToTextFmt Comme les routines précédentes, elle copie la valeur virgule flottante dans une chaîne tampon en utilisant le format spécifié.
StrToFloat Convertit la chaîne Pascal donnée en une valeur virgule flottante.
TextToFloat Convertit la chaîne à zéro terminal donnée en une valeur virgule flottante.

Conclusion

Ce chapitre a exploré la notion fondamentale de type en Pascal. Mais ce langage possède une autre caractéristique très importante : il permet aux programmeurs de définir des nouveaux types de données personnalisés. Ce sera l'objet du chapitre suivant.

Prochain chapitre: Les types de données définies par l'utilisateur
 
© Copyright Marco Cantù, Wintech Italia Srl 1995-99