|
La
programmation en pascal objet
Le Pascal est un langage fortement typé qui sert de support à Delphi.
La version utilisé par Delphi est une version enrichie appelée Pascal
Objet qui permet la programmation orienté objet dans l'environnement Windows. Ce chapitre propose une présentation du langage Pascal sous
Delphi mais n'aborde pas la programmation orintée objet.
Les règles de
base
Toutes les instructions se termine par un point virgule. Le point n’est
utilisé qu’une seule fois par unité pour en marquer la fin. On peut
écrire plusieurs instructions sur une même ligne. Un bloc
d'instruction est délimité par les instructions Begin et End.
Les directives standard du
Pascal Objet
| absolute |
far |
on |
published |
| assembler |
forward |
persistent |
resident |
| dynamic |
index |
private |
vitual |
| export |
name |
protected |
external |
| near |
public |
|
|
Les mots réservés
| and |
else |
in |
or |
to |
| asm |
end |
inherited |
packed |
try |
| array |
except |
inline |
procedure |
type |
| begin |
exports |
interface |
program |
unit |
| case |
file |
label |
record |
until |
| const |
finally |
library |
repeat |
uses |
| constructor |
for |
mod |
set |
var |
| destructor |
function |
nil |
shl |
while |
| div |
goto |
not |
shr |
with |
| do |
if |
object |
string |
xor |
| downto |
implementation |
of |
then |
|
La syntaxe
Le Pascal ne tient pas compte de la casse (minuscule/majuscule).
Une ligne de code peut être écrite sur plusieurs lignes. Le
séparateur décimal est le point.
Le style de codage
Voici quelques conseils pour rendre le code plus lisible : _ placer
les paramètres d’une fonction ou procédure sur des lignes séparées _
formatter le code source suivant le standard " bonne impression " :
indentation avec deux espace de chaque bloc de code. Ce format est utilisé
dans le code source Delphi, les manuels et les exemples d’aide.
Les commentaires
Exemple : { ceci est un commentaire } (* un autre
commentaire *) // le reste de la ligne est ignorée (seulement
depuis Delphi 2)
Pour obtenir les accolades sur un clavier n’en disposant pas, il faut
utiliser : Alt 123 et Alt 125.
Remarque : si une accolade ouverte ou la parenthèse-étoile sont suivies
du caractère dollar ($), cela devient une directive de compilation car les
directives de compilation sont des commentaires.
Exemple : {$X+ avec un commentaire} // ceci est autorisé
Variables et
constantes
La déclaration d’une variable se fait dans une clause particulière du
programme, identifiée par le mot clé var.
Les contraintes de formation d’un identificateur sont : seul les 63
premiers caracteres sont pris en compte, les caractères accentués sont
interdits, la différence minuscule/ majuscule n'est pas pris en compte, il
doit commencer par une lettre ou un souligné.
Il est possible de déclarer plusieurs variables du même type en une
seule ligne, chacunes étant séparées par une virgule.
Exemple : var valeur : integer
; fin : boolean ; car1, car2 :
char ; begin valeur :=10 ; fin
:=True ;
Portée d'une variable :
le niveau procédure : les variables sont locales à la procedure ou a la
fonction ou elles sont déclarées et sont stockées dans le segment de pile.
le niveau unité : les variables déclarées dans la section var de
l'uniré sont globales à toutes les procédures et fonctions de l'unité.
Elles sont stockées dans le segment de données du programme.
On peut accéder aux variables déclarées dans la section interface d'une
unité à partir d'un autre point du programme , ou d'un autre programme, en
déclarant la cette unité dans la section uses de l'unité appelante
Le Pascal Objet permet l’utilisation d’expression constantes :
l'affectation d'une valeur à une constante s'effectue en même temps que sa
déclaration.
const ident1 : type1 = valeur1;
Exemple : const tva := 18.6 ;
initiales : string[2] = 'JM' age : byte
= 24;
Les types de
données
Les types de
données prédéfinis
Il existe 3 groupes de types de données : les ordinaux, les réels et
les chaines
Les types ordinaux
Les types ordinaux sont fondés sur un concept d’ordre qui permet de
faire des comparaisons, d'obtenir la valeur suivante ou précédente et de
calculer la plus grande et la plus petite valeur possible.
La liste des types ordinaux est la suivante :
_ Integer, Cardinal, Shortint, SmallInt, Longint, Byte, Word _
Boolean, ByteBool, WordBool, LongBool _ Char, ANSIChar, WideChar
| Type |
Intervalle |
Longueur |
| Shortint |
-128 .. 127 |
1 octet (8 bits) |
| Integer |
-32768 .. 32767 |
2 octets |
| Longint |
-2147483648 .. 2147483647 |
4 octets |
| Byte |
0 .. 255 |
1 octets |
| Word |
0 .. 65535 |
2 octets |
| Boolean |
0, 1 (ou False, True) |
1 octets |
| Char |
0 .. 255 |
1 octets |
Byte et Word réprésentent des valeurs non signées
Integer et Cardinal utilise la représentation native ( 2 octets sur
plateforme 16 bits, 4 octets sur 32 bits) signée et non signée
respectivement.La taille des entiers varient selon le microprocesseur et
le système d’exploitation (ex : un entier est codé avec 2 octets sous
Windows 3.x, 4 octets sous Window 95).
Cela peut poser des problèmes lors de la sauvegarde dans un fichier
d’un entier sur une plateforme et la relecture sur une autre. Il faut
utiliser un type de donnée qui soit indépendant de la plateforme utilisée
( ex : LongInteger ou SmallInteger). Mais pour une utilisation normale il
est préférable d’utiliser une représentation native.
Les 4 booléens sont utiless pour la programmation avec les API
Windows.
Les 3 types de caractères sont utilisés pour indiquer des caractères 8
bits (ANSI) ou 16 bits(UniCode).
Char correspond à ANSIChar dans les versions 16 et 32 bits.
Contrairement à Windows NT, Windows 95 n’a qu’un support limité de
l’Unicode (le nouvel ensemble de caractère capable de représenter les
lettres de chacun des alphabets connus en utilisant 16 bits au lieu de 8).
Le type char est un entier compris entre 0 et 255, interpreté comme une
lettre selon le code ASCII. Une affectation du type caractère :=’q’ ; est
autorisée. La variable contiendra la valeur ASCII de la lettre sous forme
d’entier.
Il existe differentes routines systèmes pour la gestion des types
ordinaux :
| Routine |
Rôle |
| Dec |
Décrémente la variable passée en paramètre par un ou
par la valeur du second paramètre éventuel |
| Inc |
Incrémente la variable passée comme paramètre d’un
ou de la valeur spécifiée |
| Odd |
Retourne vrai si l’argument est un nombre
impair |
| Pred |
Retourne le prédécesseur de l’argument dans l’ordre
déterminée par le type de donnée |
| Succ |
Retourn le successeur |
| 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 du type ordinal passé
en paramètre |
| High |
Retoune la plus grande valeur du type ordinal passé
en paramètre |
Les types réels
Le type réels representent des nombres en virgule flottante :
_ Single, Real, Double, Extended, Comp, Currency
| Type |
Intervalle |
Longueur |
Nb chiffres pris en compte |
| Real |
2.9 * 10-39 .. 1.7 * 1038 |
6 octets |
11 - 12 |
| Single |
1.5 * 10-45 .. 3.4 * 1038 |
4 octets |
7 - 8 |
| Double |
5.0 * 10-324 .. 1.7*10328 |
8 octets |
15 - 16 |
| Extended |
3.4 * 10-4932 .. 1.1 *
104932 |
10 octets |
19 - 20 |
| Comp |
-263+1 .. 263-1 |
8 octets |
19 -20 |
Comp est en fait un type entier traité comme un type réel permettant de
décrire de très grands entiers
Currency (disponible uniquement depuis Delphi 2) indique un type en
virgule flottante avec quatre chiffres décimaux et une
représentation 64 bits pour représenter des valeurs monétaires énormes
sans perdre le moindre chiffre significatif.
Remarque : Delphi utilise des nombres réels dans les types de données
TDateTime pour stocker jour, mois, heures, minutes, secondes et
millisecondes dans une seule variable.
Les types
de données spécifiques à Windows
Ces types de données ne font partie du langage Pascal mais des
bibliothèques de Windows.
Thandle représente un Handle et est un rédéfinition du type Cardinal.
Un Handle est un code interne qui est une référence vers un élément
spécifique géré par le système. Il est utile pour appeler une API non
supportée par Delphi.
TColorRef représente une référence couleur et est une redéfinition du
type LongInt.
Le type charactère
Le type char qualifie un caractère alphanumérique. Les données de type
char sont notées entre 2 apostrophes. Affectation d'un caractere ASCII
à une variable ou une contante de type char : c := #7; Plusieurs
fonctions de l'unité System permettent de manipuler les caractères :
| Chr (X : Byte) : Char; |
Obtenir un caractère à partir de son code
ASCII |
| UpCase (c : Char) : Char; |
Convertir un caractère compris entre 'a' et 'z' en
majuscule |
Le type de donnée
Variant
La version 32 bits de Delphi introduit une nouvelle approche pour gérer
les variables pour supporter OLE Automation : le type Variant. Ces
variables peuvent stocker n’importe quel type de données. Les variants
sont vérifiés et calculés en mode exécution.
Exemple : var v : Variant ;
begin v :=10 ; v
:=’Hello’ ; ...
Une fois la valeur du variant affectée, on peut la copier vers
n’importe quel type de données compatible ou non sachant que dans ce
dernier cas, Delphi tente une conversion, si c’est possible.
Les variants stockent à la fois le type d’information et les données et
permettent un certain nombre d’opérations à l'execution. Ceci peut être
pratique mais cela s’avère souvent lent et peut sûr : il faut réserver
leurs utilisation pour utiliser OLE Automation.
Transtypage et
conversion de types
Pour assigner une variable à une autre variable d’un autre type il faut
utiliser le transtypage (Casting).
Exemple : var n : integer ;
c : char ; b : boolean ;
begin n :=Integer(‘X’) ;
c :=Char(n) ; b :=Boolean(0) ;
On peut généralement effectuer un transtypage entre deux type de
données de même taille.
Il est possible d’utiliser une routine système de conversion de type :
| Routine |
But |
| Chr |
Convertit un ordinal en caractère |
| Ord |
Convertit la valeur d’un type ordinal en nombre
indiquant son ordre |
| Round |
Convertit la valeur d’un type réel en celle d’un
type entier, en arrondissant sa valeur |
| Trunc |
Convertit la valeur d’un type réel en celle d’un
type entier, en tronquant sa valeur |
| Frac |
Renvoie la décimales d’un réel |
| Int |
Renvoie la partie entière d’un réel |
| IntToStr |
Convertit un nombre en chaine |
| IntToHex |
Convertit un nombre en chaine, avec une
représentation hexadecimale |
| StrToInt |
Convertit une chaine en nombre, en affichant une
erreur si la chaine est incorrecte |
| StrToIntDef |
Convertit une chaine en nombre, en utilisant une
valeur par défaut si la chaine est incorrecte |
| Val(s : string ; i , j :
Integer) |
Convertit une chaine s en nombre i. j contient en
cas d’erreur la position du premier caractère non convertie |
| Str |
Convertit un nombre en chaine, en utilisant des
paramètres de formatage |
| StrPas |
Convertit une chaine terminée par un caractère Null
en chaine de type Pascal |
| StrPCopy |
Convertit (copie) un chaine de style Pascal en
chaine terminée par un caractère Null |
| StrPLCopy |
Convertit (copie) une portion de chaine de style
Pascal en une chaine terminée par un Null |
Les
types de données définis par l’utilisateur
On peut définir ses propres type de données au moyen de " type
constructors " tel que les intervalles, plages, tableaux, énumerations,
pointeurs et ensembles.
La déclaration d'un type doit se faire dans une clause d'initialisation
par le mot clé type pouvant se trouver dans la clause interface d'une
unité (pour une déclaration publique) ou dans la section implementation
(pour une déclaration locale à l'unité), ou bien encore dans une fonction
ou une procedure si le type doit rester privé à ce sous programme.
Ces types peuvent recevoir un nom pour usage ultérieur ou être
appliqués directement à une variable :
Exemple : type majuscules = ‘A’ ..
‘Z’ ;
mdate = record jour : byte
; mois : Byte ;
annee : Integer ; end
;
couleurs = (bleu, vert, violet, noir) ;
lettres = set of char ; var
tableau : array [ 1 .. 31 ] of Byte ; palette : set of
couleurs
En général il faut éviter d’utiliser des types non nommés car on ne
peut pas les passer comme paramètres ou definir d’autre variable du même
type.
Les intervalles
Un intervalle se définit comme un ensemble ordonné de valeurs limitées
par une borne inférieure et par une borne supérieure. Ces valeurs
appartiennent elles-même à un type de données (prédéfini ou utilisateur)
appéllé type de base ou type hote. L'opérateur qui permet la déclaration
du type intervalle est .. (double point), selon la syntaxe suivante :
id_type : constante_inferieure .. constante_supérieure
avec nécessairement constante_inférieure < constante_supérieure
exemple : type chiffre = 0 ..
9; var c : chiffre; c := 3;
Remarque : on peut également utiliser les membres d'une énumération
pour définir un intervalle
exemple : type jours =
(lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche);
jour_ouvrables = lundi .. vendredi;
Un type intervalle définit une plage de valeurs à l’intérieur d’une
plage d’un autre type.
Exemple : type majuscules = ‘A’ ..
‘Z’ ;
Une fois définit on peut lui affecter une valeur de cette plage sinon
un message d’erreur survient " l’expression constante viole les limites de
la plage allouées ".
L’option " Verification des plages " de la page Option de compilation
est très utile lors de la phase de développement pour vérifier d'eventuel
débordement..
Les Enumérations.
Les types énumérés constituent un autre type ordinal défini par
l’utilisateur. Au lieu d’indiquer une plage d’un type existant, on liste
les valeurs possible pour le type. Une énumération est une liste de
valeurs
Exemple : type couleurs = (bleu,
vert, violet, noir);
Chaque élément d'un type énuméré est associé à une valeur numérique qui
correspond à sa position dans la liste des éléments, le premier élément
possédant la valeur 0. La déclaration de type utilise l'opérateur ()
(parenthèses) selon la syntaxe suivante :
id_type = (id_1 , id_2 , id_3 , ... , id_n);
Exemple : type jours =
(lundi,mardi,mercredi,jeudi,vendredi,samedi,dimanche);
var x : jours;
begin x := lundi;
Chaque valeur de la liste est associé à une valeur ordinale qui débute
à zéro. La fonction Ord appliquée à une valeur de type énumérée retourne
une valeur qui débute par 0. La représentation interne des type énumérés
peut différé : par défaut Delphi utilise une représentation 8 bits sauf si
il y a plus de 256 valeurs. La directive $Z permet de demander une
représentation plus grande.
Les ensembles (Set)
Un type set indique l’ensemble des possibilité d’un type ordinal,
souvent une énumération ou un intervalle, puisque le type de base ne peut
contenir plus de 256 valeurs. Chaque ensemble contient aucune, une ou plus
d’une de toutes les valeurs possibles dans la plage de type ordinal.
Exemple : type lettres =
set of majuscules ; var
lettre : lettres ;
On peut assigner des valeurs aves les instructions suivantes
Exemple : lettre := [ ‘A’, ‘B’, ‘C’] ; // assignation de
plusieurs valeurs lettre := [ ‘A’ ], // assignation d’une
seule valeur lettre := [] ; // assignation de l’ensemble
vide
Dans Delphi, les ensembles sont souvent utilisés pour indiquer des
drapeaux non exclusifs..
Les tableaux
La définition d'un type tableau unidimentionnel consiste à spécifier le
type de base et le type d'indice du tableau : Pour définir un tableau, on
utilise deux constantes de type ordinal pour spécifier les bornes du
tableau : type_tableau = array [ type_indice ] of type_composant;
Exemple : type tabentiers =
array [ 1 .. 100 ] of integer;
Le type des membres du tableau, que l'on appelle souvent des cellules,
peut être simple ou structuré, à l'exception du type fichier
Pour obtenir un tableau indéxe à partir de zéro, spécifié la valeur 0
comme borne inférieure. Exemple : ligne =
array [ 0 .. 100 ] of char;
Exemple de déclaration d'un tableau à deux dimensions :
type ecran = array [ 1 .. 24 , 1 .. 80
] of char; var ec : ecran;
Un tableau défini un nombre fixe d’éléments d’un certain type.
Utiliser les fonctions Low et High pour connaître les bornes d’un
tableau. L’utilisation de ces fonctions est fortement recommandée surtout
dans les boucles pour permettre au code de rester indépendant de la plage
du tableau. Ces fonctions sont traduites par des constantes au moment de
la compilation ce qui ne dégrade pas les temps d’execution.
Les enregistrements
Les engeristrements permettent de regrouper des types différents au
sein d'une même structure. La liste des champs composant l'enregistrement
se place entre les mots clés Record et End.
Exemple : type individu =
record nom : String;
prenom : String; age : Byte;
end; Var
ind : individu; Begin
ind.nom := 'Durand';
Exemple : type mdate = record
jour : 1 .. 31; mois : (janvier, fevrier, mars, avril, mai,
juin, juillet, aout, septembre, octobre, novembre, decembre);
annee : 1910 .. 2010; end;
L'instruction With permet de référencer de façon rapide les membres
d'un enregistrement en evitant de répéter le nom de la variable
d'enregistrement.
With nom_variable_enregistrement Do instructions End;
Exemple : with ind
do begin nom :=
'Durand'; age := 21;
end;
Un type enregistrement définit un collection fixe d’élément de types
différents.
Exemple : type pdate = record
year : Integer ; month : byte ;
day : byte ; end ;
var anniversaire : date ;
begin anniverssaire.year :=1996 ;
Les enregistrements peuvent également posséder une partie variant qui
permet d’interpréter une même zone mémoire differement.
Les pointeurs
Un pointeur définit une variable qui tient en mémoire l’adresse d’une
autre variable d’un certain type.
La définition d’un pointeur utilise la caractère spécial carret (^) :
Exemple : type pointerversint :=
^integer ;
Une fois la variable pointeur definie, on peut lui assigner l’adresse
d’une autre variable du même type en utilisant l’opérateur @ ou créer une
nouvelle variable sur le tas avec l’opérateur New.
Si un pointeur n’a pas de valeur on peut lui affecter la valeur Nil. Ce
test est souvent utiliser car déreferencer un pointeur invalide provoque
une erreur de protection générale.
Exemple : var p1,p2 : ^integer
; n : integer ; begin
n :=10 ; p1 := @n ;
new(p2) ; p1^ :=20 ; p2^ :=P1^ *
20 ; dispose(P2) ; end
;
La commande New essaie de trouver un espace mémoire correspondant à la
taille de la variable. Le pointeur contient ensuite l’adresse de la zone
mémoire réservée. S’il n’y a pas assez de place pour allouer la variable
dynamique, une exception EOutOfMemory est provoquée.
Pour pouvoir accéder au contenu de la variable sur laquelle il pointe,
il faut déférencer la variable pointeur :
pointeur^ :=valeur ;
La commande Dispose libère la mémoire allouée. La portée d’une variable
pointeur dynamique est comprise entre les instructions New et Dispose.
Il existe un type de données pointeurs qui indique des pointeurs sans
type. Avec un pointeur sans type (la taille de la mémoire variable n’est
pas définie) il faut utiliser GetMem au lieu de New.
Les pointeurs non typés sont définis par le mot clé : Pointer
Exemple : var pointeur_non_type :
Pointer ;
Ces pointeurs sont exclus du contrôle du compilateur : une utilisation
erronée provoque un plantage de l’application.
Le type fichier
(file)
Un autre constructeur de type en Pascal est le type fichier.
Exemple : type intfile = file of
integer ;
Les chaines de
caractères
Les chaines Pascal
Le type String represente une chaine de caractere possédant une
longueur variable et une taille fixe qui ne peut pas dépasser 255
caracteres, ce qui est également la valeur par défaut.
Les chaines de caracteres doivent être délimitées par des apostrophes.
Si la chaine contient elle même une apostrophe, il suffit de doubler
l'apostrophe :
s:='l''apostrophe';
Chaque caractère de la chaine est repéré par un index . Le premier
caractère possèdent la position 1 (ex: s[1] vaut 'l').
La première cellule d'une chaine possèdent la longueur de celle-ci (ex:
s[0] vaut 12).
Déclaration d'une chaine de caractères : sNom : String[30];
(String; equivaut à String[255];).
Pascal possède une façon de gérer les chaines tandis que Windows en
possède une autre. Pour accroitre la confusion la version 32 bits de
Delphi introduit le support de chaines longues.
En Pascal, la chaine typique est une séquence de caractères possèdant
un compteur de taille à son origine. Chaque chaine possède une taille
fixée par défaut à 255
Exemple : var nom : string ; //
chaine de 255 caractères titre : string[50]; // chaine
de 50 caractères
Shortstring est équivalent au chaine Pascal limitée à 255 caractères.
Les chaines Pascal sont limitées à 255 caractères. Une chaine est
presque un tableau :
Exemple : premier_car :=nom[1] ;
Par défaut, la déclaration s : string alloue l’espace mémoire
nécessaire à une variable de type AnsiString. Cette option peut être
désactivée dans le menu Projet/Options, page compilateur, groupe Option de
syntaxe, désactiver la case Chaines vastes.
Les opérateurs
de chaine de caractères
Il est possible de concatener deux chaines avec l’opérateur +.
L'opérateur + permet de concatener deux chaines de caractères (type
String) ou deux caractères (type Char) en une nouvelle chaine dont la
taille de doit pas dépasser 255 caractères pour les ShortString, sinon
elle sera tronquée. Il n’y a pas de problème acec les AnsiString.
Les opérateurs de comparaison = , <> , < , > , <= ,
>= peuvent également être employés avec des chaines de caractères. Les
chaines sont comparées d'après la valeur des codes ASCII qui la composent.
On peut aussi comparer un type String avec un type Char, car dans ce cas
ce dernier est automatiquement considéré comme une chaine de caractère
dont la longeur vaut 1.
Les
fonctions sur les chaines de caractères
| Length(S : String) :
Integer; |
obtenir la longeur actuelle d'une chaine de
caractères |
| High(X) : Integer; |
obtenir l'élément ayant l'index le plus élevé |
| Copy(S : String; Index , Count : Integer) :
String; |
extraire d'une chaine une sous chaine d'une longeur
donnée à partir d'une position donnée. Si l'on tente d'extraire plus
de caractères qu'il n'est possible, la sous chaine est
automatiquement tronquée. Si la position de l'index est supérieur à
la longueur de la chaine, on obtient une chaine vide. |
| Delete(S : String ; Index , Count :
Integer); |
suppression une sous chaine à partir d'une position
et d'une longueur donnée. La chaine de caractères doit être
nécessairement stockées dans une variable. |
| Pos(Substr : String ; S : String) : Byte; |
localiser une sous chaine. La valeur retournée est
l'index de la première occurrence de substr dans s. La valeur 0 est
retourné si la sous chaine n'est pas rencontrée. |
| CompareStr(S1 , S2 : String) :
Integer; |
comparaison de chaines. Retourne 0 si les deux
chaines sont identiques. La fonction retourne une valeur positive si
S1 est supérieur à S2, sinon elle retourne une valeur
négative. |
| CompareText( S1 , S2 : String) :
Integer; |
comparaison de chaine sans tenir compte de la
difference minuscule/majuscule |
| UpperCase(const s : String) : String; |
mettre une chaine en majuscule |
| LowerCase( const s : String) : String; |
mettre une chaine en minuscule |
| Str( i : Integer ; s : String); |
convertit une valeur numérique en chaine |
| Trim( s : String ) : String; |
Supprimer les espaces en préfixe et en suffixe |
| TrimLeft( s : String ) : String; |
Supprimer les espaces en préfixe |
| TrimRight(s : String ) : String; |
Supprimer les espaces en suffixe |
Les chaines Pascal
longues
Delphi 2 introduit le support des chaines longues pour remédier aux
limites des 255 caractères.
Les ShortStrings correspondent aux chaines Pascal normale, limitée à
255 caractères et correspondent aux chaines de la version 16 bits. Chaque
élément d’une chaine courte est de type ANSIChar (le type de caractère
standard).
ANSIString correspond aux chaines longues. Ces chaines sont allouées
dynamiquement et sont pratiquement illimitées. Elles sont fondées sur le
type ANSIChar.
Dans Delphi 2, si on utilise le type de donnée chaine, on obtient soit
une chaine courte soit une chaine ANSI selon la valeur de la directive $H
du nouveau compilateur. La valeur par défaut est $H+ qui se réfère aux
chaines longues (ANSIString utilisé aussi par la VCL).
Ces nouvelles chaines sont allouées dynamiquement : une chaine est un
pointeur vers la chaine réelle. Lorsque l’on fait une copie de la chaine,
c’est le pointeur qui est copié ce qui rend l’opération très rapide. Dès
que l’on change le contenu de l’une de ces chaines, la chaine est
dupliquée et seules les valeurs dupliqués sont affectées par le
changement. Ceci est possible grace un à mécanisme de comptage des
références du système, qui peut également libérer la mémoire lorsqu’une
chaine en mémoire n’est plus utilisée (compteur de référence à zéro).
La chaine est allouée à nouveau lorsque l’on change la taille, ce qui
implique une copie complète de la chaine si la chaine ne peut pas croitre
au même endroit. On peut affecter la taille maximale de la chaine avec la
procedure SetLength en allouant la quantité de mémoire souhaitée :
Exemple : SetLength(string1, 2000) ;
Bien que rarement nécessaire, cela peut réellement accroître le code
liée aux chaines. Lors de l’allocation d’un grande chaine, le système
réserve l’espace d’adresse pour la chaine mais ne l’alloue pas réellement
jusqu’au moment voulu.
Le seul cas on l’on doit allouer une mémoire aux chaines longues en
utilisant SetLength est lorsque cette chaine doit être passée en paramètre
à une fonction API.
Les chaines longues sont terminée par un caractère Null et sont
plainement compatible avec les chaines Windows.
Conversions de
chaines
StrPas convertit une chaine terminée par un null en chaine
Pascal courte. StrPCopy réalise l’opération en sens inverse.
Pour convertir une chaine Pascal longue en Pchar, un simple transtypage
est suffisant.
Exemple : copier la légende d’un forme en chaine en utilisant le
fonction API GetWindowText var s1 :
string ; begin SetLength(s1,100)
; GetWindowsText(button1.Handle, PChar(s1),
Length(s1)) ; end;
Si l’allocation de mémoire de SetLength échoue, le programme risque
d’interrompre tout le système.
Pour passer un paramètre à une API il suffit d’utiliser un transtypage
vers le PChar :
Exemple : SetWindowsText(Handle, PChar (Label1.Caption)) ;
Il existe des problèmes de conversions de chaines longues en PChar.
Après la conversion on devient responsable de la chaine et de son contenu.
Exemple : var s1 : string;
begin SetLength(s1,100) ;
GetWindowsText(Handle,PChar(s1),Length(s1)) ;
s1 :=s1+’ suite du texte’ ;
button1.caption :=s1 ; end;
Ce programme est compilé sans problème mais le titre du bouton ne
contient pas la constante chaine ajoutée. Lorsque Windows écrit vers la
chaine, il n’établit pas la dimension de la chaine Pascal de façon
adaptée. Delphi peut utiliser cette chaine en sortie et comprendre où elle
se termine grace au caractère null mais l’ajout de caractère ce fait après
le null.
Il faut reconvertir la chaine en chaine Pascal : exemple : s1 :=
string(s1) ; mais le système l’ignorera car elle est inutile.
Pour obtenir une chaine longue, on doit refaire un transtypage de la
chaine vers un PChar et laisser Delphi la reconvertir correctement en
chaine.
Exemple : s1 := string(PChar(s1)) ;
Les instructions
Pascal
Expressions et
opérateurs
| Opérateur |
Rôle |
| @ |
adresse de (retourne un pointeur) |
| not |
non booléen |
| * |
multiplication arithmétique ou intersection
d’ensemble |
| div |
division de réel (div est plus rapide que /) |
| mod |
division en partie entière |
| as |
typecast |
| and |
et booléen |
| shl |
glissement à gauche |
| shr |
glissement à droite |
| + |
addition, union d’ensemble, concaténation de
chaines, valeur positive, addition d’offset |
| or |
ou booléen ( l’une ou l’autre des conditions doit
être vérifiée) |
| xor |
ou exclusif booléen (soit l’une soit l’autre des
conditions doit être vérifée) |
| = |
test si égal |
| <> |
test si inégal |
| < |
test si moins que |
| > |
test si plus grand que |
| <= |
test si moins grand que ou egal, ou sous ensemble
d’un ensemble |
| >= |
test si plus grand que ou égal, ou surensemble d’un
ensemble |
| in |
test si élément dans ensemble |
| is |
test si type compatible |
Les opérateurs
d’ensemble
L’union d’ensembles : + La différence : - L’intersection : *
Le test membre de : in
Exemple : style d’un fonte style := style + [fsBold]
; style := style - [fsUnderline] ;
Instructions
simples et composées
Un instruction simple ne contient pas d’autres instructions. Elles sont
séparées par un ; Une instruction composée est déliminée par Begin ..
End ;. Le point virgule après la dernière instruction n’est pas
obligatoire. Le ; est en faite une instruction null.
Les structures de
contrôle
Les instructions
conditionnelles
if condition then instruction ;
if condition then instruction else instruction
;
Pas de ; avant le else.
case variable_ordinale of valeur1 : instruction ;
valeur2 : instruction ; else : instruction ; end
;
L’utilisation de case n’est possible que si l’on compare une variable à
un type ordinal : Integer, Char ou Boolean. Il est possible de
comparer une variable à une plage de valeur : case c of ‘a’ .. ‘f’
:
Mais Delphi refuse de compiler les plages qui se superposent. Il
est possible de faire correspondre plusieurs valeurs au libellé du case :
case c of : ‘a’,’f’ :
Les valeurs doivent obligatoirement correspondre à des valeurs
littérales et non des variables.
Les instruction
itératives
For compteur := debut To fin Do instruction
For compteur := debut DownTo fin Do instruction
While expression Do instruction
Repeat instruction Until expression
Le code de l’instruction Repeat est toujours exécuté au moins une fois.
Procédure système :
| Break |
Permet d’interrompre une boucle |
| Continue |
Permet de sauter de façon directe au test de la
boucle ou à l’incrémentation du compteur |
| Exit |
Permet de sortir de la fonction en cours |
| Halt |
Permet de terminer le programme |
L’instruction with
L’instruction With est un raccourci. Lorsque l’on réfère à un
enregistrement ou à un objet, au lieu de répéter son nom à chaque fois on
peut utiliser l’instruction with.
L’intruction goto
L’instruction goto du Pascal Objet renvoie à une étiquette qui doit
être préalablement définie dans la clause var de la procédure
Exemple : procedure TForm1.Button1Click(Sender : TObject) ;
var s : string ;
label retour ; // définition d’une étiquette
begin ... retour
: .... if
s=’’ then goto retour ;
.... end ;
L'instruction goto est à éviter.
Les
procédures et les fonctions Pascal
Les procedures
La déclaration d'une procedure se compose d'un en-tête suivi d'une
liste d'instruction délimitée par les mots clés Begin et End. L'en-tête
est également appellé prototype.
exemple : procedure test;
begin ...
end;
Pour executer cette procedure il suffit de saisir : test;
Lorque l'en-tête d'une procedure ou d'une fonction a été déclarée dans
la section interface de l'unité, il n'est pas obligatoire de reprendre
dans la partie implementation les arguments déclarées publiquement
exemple : unit utest;
interface procedure ptaxe(var
r : real); implementation
procedure ptaxe; begin
r := r * 0.186; end;
Toutes les déclarations effectuées à l'intérieur de la procedure
(variables, types, constantes, étiquettes, ...) sont locales à cette
procedure . Ces déclarations locales s'effectuent de la façon suivante :
Procedure nomproc [(listearguments)] Type ...
Const ... Var ... Begin ...
End;
Les arguments d'une
procedure
[ var | const ] nomparametre [ : type ]
Dans la déclaration d'une procedure ou d'une fonction, lorsque la liste
comprend plusieurs arguments, chaque argument passé doit être séparé par
le caractère ; (point virgule). Par contre, lors de l'appel du sous
programme, les arguments passés doivent être séparés par le caractère ,
(virgule).
Le
passage d'argument par valeur et par référence
Dans la cas d'un passage de paramètre par valeur, c'est en fait une
copie de la donnée qui est transmise. Toute modification effectuée sur la
donnée en question, à l'intérieur de la procedure appelée, n'aura aucun
effet sur la valeur de cette donnée, puisque les modifications n'auront
été justement effectuées que sur cette copie et non sur la valeur
originale. Inversement, lorque vous transmettez un argument par référence,
ce n'est pas la valeur (ou une copie de celle-ci) qui est passée à la
procedure, mais l'adresse de cette donnée. C'est pourquoi tout traitement
effectué sur le paramètre peut accéder à la donnée originale en mémoire et
peut dont effectuer des modifications sur la valeur initiale. Un paramètre
transmis par référence est précédé du mot clé var, alors qu'un paramètre
transmis par valeur ne possède aucun mot clé.
Les paramètres
constants
Les paramètres dits constants désignent un type de paramètres dont les
valeurs ne peuvent être utilisées qu'en lecture. Si vous déclarez un
paramètre avec le mot clé Const, il devient en conséquence
impossible d'affecter une quelconque valeur à l'argument actuel. Si vous
tentez de modifier la valeur de l'argument, le compilateur génère une
erreur. Le compilateur optimise le code lorque les paramètres sont des
types structurés ou des chaines de caractères.
Les fonctions
Les fonctions retourne une valeur correspodante au resultat du
traitement. Une fonction peut donc apparaître à l'intérieur d'une
expression, ce qui ne peut pas être le cas d'une procédure.
function nomfonction [(listearguments)] : type;
Exemple : function fdouble(quantite : integer)
: integer; begin fdouble :=
quantite *2; end;
Si la fonction ne possède aucun argument, les parenthèses ne devront
apparaitre ni dans l'entete, ni dans l'appel de la fonction.
Chaque fonction comprend par défaut une variable result qui
stocke le résultat de la fonction. Depuis Delphi 2, il est préférable
d’utiliser cette varaible plutôt que le nom de fonction pour donner le
résultat du traitement.
Les fichiers texte
Lorsque l’on souhaite utiliser un fichier texte, il faut suivre cinq
étapes.
Déclaration
d’une variable de fichier texte
nomdevariable : TextFile ;
Exemple : var source : TextFile
;
Affecter un
fichier à une variable
AssignFile(nomdevariable,’nomdefichier’) ;
Exemple : AssignFile(source,’c :\fichier.txt’) ;
Le nom du fichier est passé en paramètre sous forme de chaine de
caractères. Si le fichier ne se trouve pas dans le répertoire courant ou
le chemin de recherche, il faut indiquer le chemin absolu du fichier. On
peut faire référence à un fichier qui n’existe pas pour le créer .
Ouvrir un fichier
texte
Delphi possède 3 instructions pour ouvrir un fichier :
_ Rewrite(nom_de_variable) : permet de créer un fichier qui
n’existe pas. Si le fichier existe déjà, il sera simplement écrasé. Le
contenu du fichier ne sera perdu qu’à partir du moment où l’on écrit des
données dans le fichier.
_ Reset(nom_de_variable) : permet d’ouvrir un fichier en lecture
seul. Si le fichier à ouvrir n’existe pas il y aura une erreur
d’exécution.
_ Append(nom_de_variable) : permet d’ouvrir un fichier en
écriture. Les données insérées le seront en fin de fichier. Si le fichier
n’existe pas, l’application génère une erreur d’execution.
Lire un fichier texte
La fonction Readln permet de lire un fichier texte ligne après ligne.
Le " ln " fait référence à la séquence CR-LF.
Readln(variablesource,variabledestockage) ;
Exemple : var s : string ;
source : TextFile ; begin
Readln( source , s ) ; end
;
La fonction Eof permet de détecter la fin d’un fichier. Elle
prend comme paramètre la variable qui pointe sur le fichier. Eof renvoie
True lorsque la fin du fichier est atteinte.
Exemple : while not Eof(source) do
Ecrire dans une fichier
texte
La fonction Writeln permet d’écrire un fichier texte.
Writeln(variablesource,variabledestockage) ;
Il existe une procedure Write qui permet d’écrire une ligne en plusieur
fois mais il est indispensable d’utiliser Writeln à la fin pour passer à
la ligne.
Fermeture d’un
fichier
La fermeture des fichiers est importaent car elle libère les ressources
exigées par le fichier et permet une réelle écriture des données sans
risque de perte d’information.
CloseFile(variablesource) ;
Test d’existence d’un
fichier
FileExists(‘nomdeficheir’) : Boolean
Exemple : var F : TextFile ;
... AssignFile(F,’c :\fichier.txt’)
; if FileExists(‘c :\fichier.txt’) then Append(
F ) else Rewrite( F ) ; ...
Close( F ) ;
Les
directives de compilation pour gérer les erreurs d’E/S
Pour éviter que le déroulement d’une application ne s’interrompe en cas
d’abscence d’un fichier, il faut désactiver la vérification d’entrée
sortie en utilisant la directive {$I+/-}
Exemple : var F : TextFile ;
I : Integer ...
AssignFile(F,’c :\fichier.txt’) ; {$I-}
Append(F) ; {I+} I
:=IOResult ; if( I = 2 ) then Rewrite( F ); // le
fichier n’existe pas ...
CloseFile( F ) ;
Le résultat d’une évaluation est stockée dans la variable IOResult
déclarée implicitement. La valeur de la variable doit être stockée dans
une autre variable car le simple fait d’appeler IOResult la vide de son
contenu.
Directive de compilation
La directive de compilation {$I-}
permet au programmeur de se prémunir des arrêts du programme suite à
l'absence d'un fichier, l'impossibilté de l'ouvrir en écriture, ... En
effet, cette directive lui permet de gérer lui-même ces problèmes. Les
éventuelles erreurs sont renvoyées dans la variable IOResult. Il est à
noter que le contenu de cette variable est détruit lors de son
utilisation. Il faut donc mieux le stocker de l'employer.
{$I-}
ASSIGN(File, FileName);
RESET(File);
CLOSE(File);
{$I+}
Err:=IOResult;
CASE Err OF
0 : WRITELN('No error'.);
2 : WRITELN('File not found');
3 : WRITELN('Path not found');
4 : WRITELN('Too many open files');
5 : WRITELN('File access denied');
12 : WRITELN('Invalid file access code');
15 : WRITELN('Invalid drive number');
16 : WRITELN('Cannot remove current directory');
17 : WRITELN('Cannot rename across drives');
18 : WRITELN('No more files');
100 : WRITELN('Disk read error');
101 : WRITELN('Disk write error');
102 : WRITELN('File not assigned');
103 : WRITELN('File not open');
104 : WRITELN('File not open for input');
105 : WRITELN('File not open for output');
106 : WRITELN('Invalid numeric format');
150 : WRITELN('Disk is write-protected);
152 : WRITELN('Drive not ready');
ELSE WRITELN('Error #, Err);
END; |