- Variables et constantes
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 nest utilisé quune 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 |
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 dune 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 daide.
Les commentaires
Exemple :
{ ceci est un commentaire }
(* un autre commentaire *)
// le reste de la ligne est ignoré (seulement depuis Delphi 2)
Pour obtenir les accolades sur un clavier nen 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 dune variable se fait dans une clause particulière du programme, identifiée par le mot clé var.
Les contraintes de formation dun 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 lutilisation dexpression 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 dordre 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 dexploitation (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 dun 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 dutiliser 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 na quun support limité de lUnicode (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 dentier.
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 dun ou de la valeur spécifiée |
Odd | Retourne vrai si largument est un nombre impair |
Pred | Retourne le prédécesseur de largument dans lordre déterminée par le type de donnée |
Succ | Retourn le successeur |
Ord | Retourne un nombre indiquant lordre de largument dans lensemble 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 nimporte 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 nimporte quel type de données compatible ou non sachant que dans ce dernier cas, Delphi tente une conversion, si cest possible.
Les variants stockent à la fois le type dinformation et les données et permettent un certain nombre dopérations à l'execution. Ceci peut être pratique mais cela savè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 dun 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 types de données de même taille.
Il est possible dutiliser une routine système de conversion de type :
Routine | But |
Chr | Convertit un ordinal en caractère |
Ord | Convertit la valeur dun type ordinal en nombre indiquant son ordre |
Round | Convertit la valeur dun type réel en celle dun type entier, en arrondissant sa valeur |
Trunc | Convertit la valeur dun type réel en celle dun type entier, en tronquant sa valeur |
Frac | Renvoie la décimales dun réel |
Int | Renvoie la partie entière dun 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 derreur 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 lutilisateur
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 dutiliser des types non nommés car on ne peut pas les passer comme paramètres ou definir dautre 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 à lintérieur dune plage dun autre type.
Exemple :
type
majuscules = A .. Z ;
Une fois définit on peut lui affecter une valeur de cette plage sinon un message derreur survient " lexpression constante viole les limites de la plage allouées ".
Loption " 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 lutilisateur. Au lieu dindiquer une plage dun 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 lensemble des possibilité dun 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 dune 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 dune seule valeur
lettre := [] ; // assignation de lensemble 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 dun certain type.
Utiliser les fonctions Low et High pour connaître les bornes dun tableau. Lutilisation 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 dexecution.
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 dinterpréter une même zone mémoire differement.
Les pointeurs
Un pointeur définit une variable qui tient en mémoire ladresse dune autre variable dun certain type.
La définition dun pointeur utilise la caractère spécial carret (^) :
Exemple :
type
pointerversint := ^integer ;
Une fois la variable pointeur definie, on peut lui assigner ladresse dune autre variable du même type en utilisant lopérateur @ ou créer une nouvelle variable sur le tas avec lopérateur New.
Si un pointeur na 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 ladresse de la zone mémoire réservée. Sil ny 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 dune 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 nest 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 controle du compilateur : une utilisation erronée provoque un plantage de lapplication.
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 lespace 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 lopé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 ny 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 dune 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 lon fait une copie de la chaine, cest le pointeur qui est copié ce qui rend lopération très rapide. Dès que lon change le contenu de lune 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 lorsquune chaine en mémoire nest plus utilisée (compteur de référence à zéro).
La chaine est allouée à nouveau lorsque lon 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 accroitre le code liée aux chaines. Lors de lallocation dun grande chaine, le système réserve lespace dadresse pour la chaine mais ne lalloue pas réellement jusquau moment voulu.
Le seul cas on lon 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 lopération en sens inverse.
Pour convertir une chaine Pascal longue en Pchar, un simple transtypage est suffisant.
Exemple : copier la légende dun 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 lallocation de mémoire de SetLength échoue, le programme risque dinterrompre tout le système.
Pour passer un paramètre à une API il suffit dutiliser 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 lajout 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 lignorera 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 densemble |
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 densemble, concaténation de chaines, valeur positive, addition doffset |
or | ou booléen (lune ou lautre des conditions doit être vérifiée) |
xor | ou exclusif booléen (soit lune soit lautre 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 dun ensemble |
>= | test si plus grand que ou égal, ou surensemble dun ensemble |
in | test si élément dans ensemble |
is | test si type compatible |
Les opérateurs densemble
L'union d'ensembles : +
La différence : -
Lintersection : *
Le test membre de : in
Exemple : style dun fonte
style := style + [fsBold] ;
style := style - [fsUnderline] ;
Instructions simples et composées
Un instruction simple ne contient pas dautres 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 nest pas obligatoire.
Le ; est en faite une instruction null.
Les structures de controle
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 ;
Lutilisation de case nest possible que si lon 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 instructions 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 linstruction Repeat est toujours exécuté au moins une fois.
Procédure système :
Break | Permet dinterrompre une boucle |
Continue | Permet de sauter de façon directe au test de la boucle ou à lincrémentation du compteur |
Exit | Permet de sortir de la fonction en cours |
Halt | Permet de terminer le programme |
Linstruction with
Linstruction With est un raccourci. Lorsque lon réfère à un enregistrement ou à un objet, au lieu de répéter son nom à chaque fois on peut utiliser linstruction with.
Lintruction goto
Linstruction 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 dune é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 dutiliser cette variable plutôt que le nom de fonction pour donner le résultat du traitement.
Les fichiers texte
Lorsque lon souhaite utiliser un fichier texte, il faut suivre cinq étapes.
Déclaration dune 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 nexiste 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 nexiste 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 douvrir un fichier en lecture seul. Si le fichier à ouvrir nexiste pas il y aura une erreur dexécution.
- Append(nom_de_variable) : permet douvrir un fichier en écriture. Les données insérées le seront en fin de fichier. Si le fichier nexiste pas, lapplication génère une erreur dexecution.
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 dun 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 dutiliser Writeln à la fin pour passer à la ligne.
Fermeture dun 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 dinformation.
CloseFile(variablesource) ;
Test dexistence dun 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 dE/S
Pour éviter que le déroulement dune application ne sinterrompe en cas dabscence dun fichier, il faut désactiver la vérification dentré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 nexiste pas
...
CloseFile( F ) ;
Le résultat dune é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 dappeler IOResult la vide de son contenu.