FAQ PascalConsultez toutes les FAQ
Nombre d'auteurs : 10, nombre de questions : 402, dernière mise à jour : 7 janvier 2018 Ajouter une question
Bienvenue dans la F.A.Q. Pascal !
Celle-ci rassemble les réponses aux questions les plus fréquemment posées sur le langage Pascal et tous ses outils de programmation. Si elle n'a pas pour vocation de répondre à toutes les interrogations possibles, elle reste une bonne base de connaissances sur le Pascal, et ne demande qu'à être enrichie par vos expériences personnelles.
Nous vous invitons à proposer vos propres questions/réponses directement dans la FAQ ou, si vous souhaitez apporter une modification à une question/réponse existante, à la poster dans le fil de discussion renseigné ci-dessous.
Nous vous souhaitons une bonne lecture !
L'équipe Pascal.
- 2.1. Les chaînes de caractères de type string (8)
- 2.2. Les chaînes de caractères à zéro terminal (12)
- 2.3. Les nombres (9)
- 2.4. Les fichiers (10)
- 2.5. Les erreurs courantes (3)
- 2.6. Généralités (6)
- Qu'est-ce qu'un mot réservé ?
- Qu'est-ce qu'un type scalaire ?
- Qu'est-ce qu'un type structuré ?
- A quoi sert la directive packed ?
- Qu'est-ce que le transtypage ?
- Comment déclarer une constante typée de type structuré ?
- Quelle est la différence entre une procédure et une fonction ?
- Comment déclarer des procédures qui s'appellent mutuellement ?
- Deux unités peuvent-elles se référencer mutuellement ?
- Quels sont les modes de transmission d'un paramètre à une procédure ou fonction ?
- Un paramètre transmis par valeur est-il toujours déposé sur la pile ?
- Pourquoi est-il préférable de transmettre un paramètre comme constante plutôt que par valeur ?
- Une fonction peut-elle retourner un résultat de type structuré ?
- Comment simplifier une imbrication de blocs If...then...else ?
- Faut-il mettre un point-virgule à la fin d'une instruction précédant un end ?
- Comment se sert-on de l'instruction goto ?
- Comment utiliser la compilation conditionnelle ?
- Pourquoi peut-il être utile d'inclure de l'Assembleur dans un programme ?
- Comment inclure de l'Assembleur dans un programme ?
Un mot réservé fait partie intégrante de la syntaxe du langage Pascal ou est une instruction spécifique au langage. Il est interdit d'utiliser un mot réservé comme nom de variable, de procédure ou de type. Vous pouvez reconnaître aisément les mots réservés dans la plupart des EDI : par défaut, ils apparaissent en contraste ou en gras.
Les principaux mots réservés du Pascal sont : begin, end, if, then, else, for, to, do, while, repeat, until, and, or, not, const, type, var, string, etc.
Les types scalaires (ordinal types en anglais) sont une catégorie de types qui définissent des ensembles de valeurs ordonnées, à l'exception des types réels (qui forment une classe à part). Pour essayer d'être plus clair, on les appelle ainsi parce qu'on peut déterminer leur rang, qui est leur valeur entière.
Les types scalaires du Pascal sont les suivants :
- Char
- Boolean
- LongBool (Free Pascal, Virtual Pascal, Delphi)
- ShortInt
- Byte
- Integer
- SmallInt (Free Pascal, Virtual Pascal, Delphi)
- Word
- LongInt
- LongWord (Free Pascal, Delphi)
- Cardinal (Free Pascal, Virtual Pascal, Delphi)
- Int64 (Delphi uniquement - voir remarque ci-dessous)
- Type énuméré
- Intervalle
Le compilateur Free Pascal propose également un type entier non signé sur 64 bits, QWord. Il est à noter que, pour Free Pascal, les types QWord et Int64, ne sont pas scalaires et ne sont pas utilisables dans certaines expressions.
Un type structuré est un type qui comporte plus d'un élément dans sa déclaration.
Les types structurés possibles dans le langage Pascal sont les suivants :
- Array (tableau)
- Set (ensemble)
- File (fichier)
- Record (enregistrement)
- Object (objet)
- Class (classe - Free Pascal, Virtual Pascal, Delphi)
- Interface (interface - Free Pascal, Delphi)
La directive packed peut préfixer n'importe quel type structuré (array, record, set...). Héritage des machines des années '70, elle provoquait un stockage plus compact des types structurés.
Toutes les versions du compilateur Turbo Pascal ignorent carrément cette directive car tous les types structurés sont automatiquement compactés. Les compilateurs Free Pascal, Virtual Pascal et Delphi, par contre, utilisent un alignement par défaut du contenu des types structurés sur 32 bits. La directive packed compacte le contenu sans tenir compte de cet alignement par défaut.
Le transtypage (typecast en anglais) est une technique permettant de demander au compilateur de considérer une variable d'un certain type comme étant d'un autre type. Il est primordial que les deux types aient la même taille, sans quoi une erreur de compilation sera déclenchée.
Voici un exemple simple : incrémenter une variable de type caractère (pour transformer un 'A' en 'B'). La 1ère version ne fonctionne pas mais la seconde oui, grâce au transtypage du caractère en byte (les types char et byte sont de même taille) :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 | Var x : Char; Begin x := 'a'; x := x + 1; { Déclenche une erreur de compilation } End; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 | Var x : Char; Begin x := 'a'; Byte(x) := Byte(x) + 1; { x contient 'B' } End; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | Type Tab = Array [1..4] of Byte; Rec = Record w1, w2 : Word; end; Var r : Rec; Begin r.w1 := $0102; r.w2 := $FEFF; WriteLn(Tab(r)[1]); { Affiche '2' } End; |
- Tableaux
Pour déclarer une constante typée de type tableau, il faut soigneusement délimiter les valeurs à l'aide de parenthèses.
Voici un exemple de tableau à deux dimensions :
Code delphi : | Sélectionner tout |
1 2 3 4 | Type tTabCoord = Array [1..2,1..3] of Integer; Const Coordonnees : tTabCoord = ((0,0,24),(0,48,12)); |
- Enregistrements ou objets
Pour déclarer une constante typée de type enregistrement ou objet, il faut spécifier le nom de chaque champ et, surtout, veiller à respecter l'ordre des champs de la déclaration de type.
Voici un exemple d'enregistrement :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | Type tRecCoord = Record Nom : String [25]; x, y : Integer; end; Const Coordonnees : tRecCoord = (Nom : 'Vaisseau alien'; x : 100; y : 25); |
Les procédures et les fonctions permettent toutes deux de regrouper plusieurs instructions se répétant dans un programme , pour éviter d'avoir à réécrire un même code plusieurs fois. Elles permettent aussi d'automatiser des tâches, et surtout de clarifier et donc simplifier votre code.
Mais les fonctions font une chose que les procédures ne font pas : elles renvoient un résultat.
Prenons deux exemples. Si vous voulez calculer la somme de deux nombres, vous attendez un résultat : vous utiliserez une fonction. Si vous voulez effacer l'écran, vous attendez seulement que l'écran soit effacé, donc pas de résultat concret à traiter : vous utiliserez plutôt une procédure.
Code delphi : | Sélectionner tout |
1 2 3 | Function Exemple1 : Integer; { On renvoie un résultat de type Integer } Procedure Exemple2; { On ne renvoie aucun résultat } |
Lorsque deux procédures doivent s'appeler mutuellement, il faut choisir dans quel ordre les déclarer.
A supposer que la procédure Proc1 doive appeler la procédure Proc2 et réciproquement, doit-on délarer Proc1 avant Proc2 ou bien l'inverse ?
Il suffit de faire l'essai pour se rendre compte qu'aucune des deux versions ne fonctionnera. Ainsi, le code suivant provoquera une erreur à la compilation :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | Procedure Proc1 (n : Integer); Begin if n > 0 then Proc2(n - 1); End; Procedure Proc2 (n : Integer); Begin if n > 0 then Proc1(n - 1); End; |
Notre problème se résout donc de la manière suivante :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { On délare en tant que forward, comme on le ferait dans une unité - partie interface } Procedure Proc2 (n : Integer); forward; Procedure Proc1 (n : Integer); Begin if n > 0 then Proc2(n - 1); End; { On complète la déclaration, comme on le ferait dans une unité - partie implementation } Procedure Proc2 (n : Integer); Begin if n > 0 then Proc1(n - 1); End; |
Il est tout-à-fait possible de faire en sorte qu'une unité U1 fasse appel à des routines de l'unité U2 et que cette dernière fasse appel à des routines de l'unité U1. Le tout est d'éviter l'erreur de compilation 68 "circular unit reference".
Pour ce faire, il faut tout simplement que la clause uses d'une des deux unités ne se trouve pas dans la partie interface de l'unité, mais bien dans la partie implémentation.
Exemple :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Unit U1; Interface Procedure Proc1; Implementation Uses U2; Procedure Proc1; Begin Proc2; WriteLn('Proc 1'); End; End. |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Unit U2; Interface Uses U1; Procedure Proc2; Procedure Proc3; Implementation Procedure Proc2; Begin WriteLn('Proc 2'); End; Procedure Proc3; Begin Proc1; WriteLn('Proc 3'); End; End. |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | Program UX; Uses WinCRT, U1, U2; Begin Proc1; Proc2; Proc3; End. |
Il existe quatre modes de transmission d'un paramètre à une procédure ou fonction. Un exemple concret permettra de mieux les comprendre :
Code delphi : | Sélectionner tout |
1 2 | Procedure MaProc (a : Integer; var b : Integer, const c : Integer; out d : Integer); |
- Le paramètre a est transmis par valeur : sa valeur est déposée sur la pile pour être utilisée dans la procédure. Même si la valeur de a est modifiée à l'intérieur de la procédure, elle restera inchangée pour le programme appelant.
- Le paramètre b est transmis par adresse : c'est non pas sa valeur mais son adresse qui est déposée sur la pile de sorte que, si sa valeur est modifiée au sein de la procédure, elle est également modifiée pour le programme appelant.
- Le paramètre c est transmis comme constante : si sa taille est inférieure ou égale à la taille d'un pointeur, il est transmis par valeur; sinon, il est transmis par adresse. Dans l'exemple, c est de type entier, donc sa taille égale celle d'un pointeur : c est donc transmis par valeur. La valeur d'un paramètre transmis comme constante ne peut être modifiée au sein de la procédure ou fonction.
- Le paramètre d est transmis comme output : il est en fait transmis par adresse mais sa valeur initiale est ignorée par la procédure. Par contre, s'il reçoit une valeur au sein de la procédure, elle sera prise en compte par le programme appelant.
Turbo Pascal ne supporte que la transmission par valeur et par adresse.
Il arrive que le compilateur transforme une transmission par valeur d'un paramètre à une procédure ou fonction en transmission par adresse.
Free Pascal, Virtual Pascal, Delphi :
- Entiers sur 1 octet : dépôt sur la pile d'un double-mot (octet de poids faible du double-mot);
- Entiers sur 2 octets : dépôt sur la pile d'un double-mot (mot de poids faible du double-mot);
- Entiers sur 4 octets : dépôt sur la pile d'un double-mot;
- Entiers sur 8 octets : dépôt sur la pile de 2 doubles-mots;
- Char : dépôt d'un double-mot sur la pile (le caractère étant l'octet de poids faible);
- Boolean : dépôt d'un double-mot sur la pile (le booléen étant l'octet de poids faible);
- LongBool : dépôt d'un double-mot sur la pile;
- Enuméré : dépôt d'un double-mot sur la pile (octet de poids faible si maximum 256 valeurs);
- Single : dépôt d'un double-mot sur la pile;
- Real, double, comp : dépôt de 2 doubles-mots sur la pile;
- Extended : dépôt de 3 doubles-mots sur la pile (les 10 octets de poids faible);
- Pointeurs : dépôt d'un double mot (offset);
- String : dépôt de l'adresse de la chaîne (donc, d'un pointeur);
- Set : dépôt de l'adresse (pointeur);
- Array : dépôt sur la pile si taille <= 8 octets. Sinon dépôt de l'adresse;
- Record : dépôt sur la pile si taille <= 8 octets. Sinon dépôt de l'adresse.
Turbo Pascal :
- Entiers : dépôt sur la pile d'un ou 2 mots (entier sur 1 octet : octet de poids faible du mot déposé);
- Char : dépôt d'un mot sur la pile (le caractère étant l'octet de poids faible);
- Boolean : dépôt d'un mot sur la pile (le booléen étant l'octet de poids faible);
- Enuméré : dépôt d'un mot sur la pile (octet de poids faible si maximum 256 valeurs);
- Real : dépôt de 6 octets sur la pile;
- Single, double, extended, comp : chargement dans la pile du coprocesseur;
- Pointeurs : dépôt d'un double mot (segment puis offset);
- String : dépôt de l'adresse de la chaîne (donc, d'un pointeur);
- Set : dépôt de l'adresse (pointeur);
- Array : dépôt sur la pile si taille <= 4 octets. Sinon dépôt de l'adresse;
- Record : dépôt sur la pile si taille <= 4 octets. Sinon dépôt de l'adresse.
Il est à noter que, dans le cas de la transmission par valeur, lorsque c'est l'adresse du paramètre qui est déposée sur la pile, une copie locale de la variable est réalisée au début de la procédure ou fonction.
Lorsque c'est possible, il faut privilégier le mode de transmission d'un paramètre à une procédure ou à une fonction comme constante plutôt que par valeur. Ce principe est surtout valable pour des types de grande taille.
Pourquoi ?
Lorsqu'un paramètre est transmis par valeur, le compilateur réserve dans la pile un espace de la taille du paramètre et réalise une copie de celui-ci. Tandis que, lorsque le paramètre est transmis comme constante, seule son adresse est déposée sur la pile, exactement comme lors d'une transmission par adresse.
La réponse dépend du compilateur utilisé : alors que Free Pascal et Virtual Pascal permettent sans problème à une fonction de retourner un résultat de type structuré (un record, par exemple), Turbo Pascal ne peut retourner qu'un type simple.
Pour contourner cette limitation, dans un programme Turbo Pascal, on utilisera un paramètre par adresse.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Var Date : tDateTime; Function DATE_DU_JOUR : tDateTime; Var JourSemaine : Word; Begin GetDate(Result.Year,Result.Month,Result.Day,JourSemaine); End; Begin Date := DATE_DU_JOUR; WriteLn(Date.Day,'-',Date.Month,'-',Date.Year); ReadLn; End. |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Var Date : tDateTime; Procedure DATE_DU_JOUR (var Result : tDateTime); Var JourSemaine : Word; Begin GetDate(Result.Year,Result.Month,Result.Day,JourSemaine); End; Begin DATE_DU_JOUR(Date); WriteLn(Date.Day,'-',Date.Month,'-',Date.Year); ReadLn; End. |
Une imbrication de blocs de cette forme :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | if X = A then DoA else if X = B then DoB else if X = C then DoC else if X = D then DoD else DoE; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | case X of A : DoA; B : DoB; C : DoC; D : DoD: else DoE; end; |
L'absence de point-virgule juste avant un end est définie dans la syntaxe standard du Pascal. Par exemple :
Code delphi : | Sélectionner tout |
1 2 3 4 | ... i := 2 end; |
Tous les compilateurs actuels acceptent qu'il y ait un point virgule; on peut donc considérer que le débat est devenu sans objet et que le choix de mettre ou pas le point virgule est laissé à la discrétion du programmeur.
Bien qu'elle soit conspuée dans toutes les écoles de programmation (du moins, dans les cours utilisant le Pascal), l'instruction goto existe depuis les débuts du Pascal et est rencontrée de loin en loin. Son impopularité vient du fait qu'elle est souvent considérée comme un échec de logique dans la conception d'un programme. Sans prendre parti, voici son fonctionnement.
Très important : une instruction goto ne peut référencer un label situé en dehors du même bloc de code.
Grâce à une directive label, souvent située au début du source, on déclare les labels utilisés dans le programme (s'il y en a plusieurs, ils seront séparés par des virgules). Un label peut être un identificateur ou une constante numérique. A l'intérieur du code, le label est inséré avant une instruction. Il est suivi de deux points (:), comme en Assembleur.
Exemple :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | Program TestGoto; Label Fin; Begin ... goto Fin; ... Fin: Halt(0); End; |
Il peut être bien pratique d'indiquer au compilateur qu'il doit, sous certaines conditions, compiler ou pas certaines parties du source. On peut soit définir soi-même des symboles et tester leur existence durant le processus de compilation, soit utiliser des symboles prédéfinis.
Symboles
Pour définir soi-même un symbole, on utilise la directive {$DEFINE} :
Code delphi : | Sélectionner tout |
1 2 |
{$DEFINE MaCondition} |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 | {$DEFINE MaCondition} ... {$UNDEF MaCondition} |
Symbole | Signification |
CPU86 | CPU de la famille Intel 80x86 (ou compatible) |
CPU87 | Coprocesseur 80x87 détecté |
DPMI | Compilation en mode protégé |
MSDOS | Compilation en mode réel |
VER70 | N° de version de Turbo Pascal |
WINDOWS | Environnement Windows détecté |
Symbole | Signification |
CPU86 / CPU87 | CPU de la famille Intel 80x86 (ou compatible) |
CPUI386 | CPU Intel 80386 et ultérieur (ou compatible) |
CPU68K / CPU68 | CPU de la famille Motorola 68xxx (ou compatible) |
CPU68020 | CPU Motorola 68020 et ultérieur (ou compatible) |
CPUSPARC | CPU SPARC v7 (ou compatible) |
CPUALPHA | CPU Alpha AXP (ou compatible) |
CPUX86_64 / CPU64 | CPU AMD ou Intel 64 bits |
CPU32 | CPU 32 bits sans plus de précision |
WIN32 | Compilation pour plate-forme Win32 |
WIN64 | Compilation pour plate-forme Win64 |
WINCE / UNDER_CE | Compilation pour plate-forme Windows CE |
WINDOWS / MSWINDOWS | Compilation pour plate-forme Windows sans plus de précision |
LINUX | Compilation pour plate-forme Linux |
FREEBSD | Compilation pour plate-forme FreeBSD |
NETBSD | Compilation pour plate-forme NetBSD |
SUNOS / SOLARIS | Compilation pour plate-forme Sun |
DPMI / GO32V2 | Compilation en mode protégé 32 bits |
OS2 | Compilation pour plate-forme OS/2 (32) |
AMIGA | Compilation pour plate-forme Amiga |
ATARI | Compilation pour plate-forme Atari |
MAC / MACOSX | Compilation pour plate-forme Macintosh |
PALMOS | Compilation pour plate-forme PalmOS |
CPUPOWERPC | Compilation pour PowerPC (32) (ou compatible) |
Symbole | Signification |
CPU86 / CPU386 | CPU de la famille Intel 80x86 (ou compatible) |
CPU87 | Coprocesseur 80x87 détecté |
DPMI32 | Compilation en mode protégé 32 bits |
WIN32 | Compilation pour la plate-forme Win32 |
LINUX | Compilation pour la plate-forme Linux |
OS2 | Compilation pour la plate-forme OS/2 (32) |
USE32 | Code objet 32 bits (surtout utile pour du code Assembleur) |
VER21 | N° de version de Virtual Pascal |
Les directives {$IFDEF} et {$IFNDEF} testent respectivement la définition et la non-définition d'un symbole conditionnel.
On rencontre les constructions suivantes :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 | {$IFDEF MaCondition} ... {$ELSE} ... {$ENDIF} |
Code delphi : | Sélectionner tout |
1 2 3 4 | {$IFNDEF MaCondition} ... {$ENDIF} |
Exemple :
Code delphi : | Sélectionner tout |
1 2 3 4 | {$IFOPT I+} ... {$ENDIF} |
L'Assembleur est le langage de programmation le plus proche de la machine qui puisse être compris relativement simplement par l'homme. Contrairement au Pascal, qui appartient aux langages dits de "haut niveau", l'Assembleur est un langage de "bas niveau".
Relativement obscur pour les néophytes, l'Assembleur est néanmoins le seul outil existant pour pallier aux lacunes du Pascal. En effet, le Pascal, bien que très polyvalent, ne sait pas tout faire, et il est parfois nécessaire de faire appel à un langage plus spécialisé, tel l'Assembleur, pour accéder au coeur de la machine. Un bon exemple est l'inclusion d'instructions 32 bits dans un programme Turbo Pascal.
L'Assembleur peut aussi être utilisé dans les routines dites "critiques", autrement dit qui nécessitent des performances accrues.
Pour ajouter de l'assembleur dans votre programme, vous pouvez soit ajouter un bloc asm...end; soit créer une procédure en assembleur, en ajoutant la directive assembler à sa déclaration :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 | Begin ... asm ... end; ... End; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 | Procedure TestAsm; assembler; asm ... end; |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.