Si può considerare una variabile come un contenitore dove andare ad immagazzinare un informazione. Questa informazione può variare nel tempo, proprio per questo si chiama variabile. Si può considerare una costante al pari di una variabile ma una volta riempita con un valore quello rimane fisso fino alla fine del programma. Quando si dichiara una variabile si occupa dello spazio in memoria per tutta la durata del programma o della funzione o della procedura, dipende dove questa variabile è dichiarata. Si può anche dire allocare in memoria una variabile. Affronteremo questo capitolo in maniera pratica come sarà di consuetudine in questo blog.
Per prima cosa creiamo una nuova Applicazione in Lazarus: File -> Nuovo… -> Applicazione
Come visto in precedenza, salviamo il nostro progetto in una directory. Sulla form che comparirà aggiungiamo una TMemo e un TButton, come nell’immagine che segue.
Facciamo doppio click sul pulsante, automaticamente lazarus creerà l’evento principale associato al componente, come nell’immagine che segue.
Ora scriviamo nella “procedure” Button1Click quanto segue
procedure TForm1.Button1Click(Sender: TObject);
var
PrimaVariabile : char;
SecondaVariabile : integer;
TerzaVariabile, QuartaVariabile : double;
QuintaVariabile : string;
const
MiaCostante = 5;
begin
Memo1.Clear;
PrimaVariabile := 'B';
SecondaVariabile := 0;
SecondaVariabile := SecondaVariabile + 2;
TerzaVariabile := 3.3 + 1;
QuartaVariabile := TerzaVariabile + 1;
QuintaVariabile := 'Ecco a cosa servono le variabili! Fine';
Memo1.Append('PrimaVariabile : ' + PrimaVariabile);
Memo1.Append('SecondaVariabile: ' + IntToStr(SecondaVariabile));
Memo1.Append('TerzaVariabile : ' + FloatToStr(TerzaVariabile));
Memo1.Append('QuartaVariabile : ' + FloatToStr(QuartaVariabile));
Memo1.Append('QuintaVariabile : ' + QuintaVariabile);
Memo1.Append('Costante : ' + IntToStr(MiaCostante));
end;
Ora analizziamo quello che abbiamo appena fatto. Prendiamo in esame l’ultima modifica effettuata, var è una parola riservata che sta a significare che voglio dichiarare delle variabili o delle costanti. Dichiarare vuol dire che si decide che tipo di contenuto può possedere la variabile in questione, ad esempio un numero intero, un numero con la virgola, un carattere alfanumerico, stringa, o altro.
PRECISAZIONE: a differenza di altri linguaggi (ad esempio il C), in pascal non esiste differenza tra maiuscolo e minuscolo nelle dichiarazioni di variabili, procedure o altro e nelle “parole chiavi”, per cui VAR o Var o var sono la stessa cosa, così come PrimaVariabile o Primavariabile o primavariabile.
Consideriamo solo le variabili che abbiamo aggiunto noi, la prima si chiama PrimaVariabile ed è definita come char, ovvero può contenere un carattere. La seconda si chiama SecondaVariabile ed è definita integer, ovvero un tipo numerico intero come il 5 o 8 ma non ad esempio 4,5 o 4.3. La TerzaVariabile e la QuartaVariabile sono di tipo double ovvero numerico con la virgola. Mentre la QuintaVariabile è di tipo string ovvero può contenere una insieme di lettere e/o cifre come una parola o una frase alfanumerica. E poi per ultima la costante MiaCostante, che avrà il valore 5 per tutta la vita della procedura. Ora vediamo in pratica come si differenzia una variabile da una costante. Come si può notare nella prima parte di codice che abbiamo modificato in questo programma abbiamo assegnato dei valori alle variabili e poi le abbiamo stampate a video, e poi nuovamente rivalorizzate e successivamente ristampate. Se il lettore si prendesse la briga di provare a riassegnare un valore alla costante noterebbe che in fase di compilazione del programma si otterrebbe un errore, perchè una costante non può essere rivalorizzata dopo essere stata dichiarata. Compilando attraverso il solito pulsantino che contiene un triangolino verde saremo in grado di vedere il risultato del nostro articolo.
I tipi principali delle variabili disponibili nel linguaggio free pascal sono: integer, shortint, smallint, longint, longword, int64, byte, word, qword, boolean, bytebool, longbool, char.
Per quanto riguarda i tipi numerici li possiamo così classificare:
Tipo | Range | Dimensione in bytes |
Byte | 0..255 | 1 |
Shortint | -128..127 | 1 |
Smallint | -32768..32767 | 2 |
Word | 0..65535 | 2 |
Integer | o Smallint o Longint | 2 o 4 |
Longint | -2147483648 .. 2147483647 | 4 |
Longword | 0..4294967295 | 4 |
Int64 | -9223372036854775808 .. 9223372036854775807 | 8 |
QWord | 0 .. 18446744073709551615 | 8 |
Per quanto riguarda il tipo integer, che può variare da smallint a longint, è il freepascal a definirne la “grandezza” in base alla CPU / sistema operativo per cui dovrà essere compilato.
In FPC (e quindi in Lazarus) esistono degli alias già predefiniti per l’uso comune, ad esempio UInt64 che fornisce immediatamente una immagine del contenuto rispetto a Qword, o Cardinal che è usato comunemente anche in tanti altri linguaggi rispetto a LongWord.
Questo è l’elenco di alias già dichiarati in Lazarus:
Alias | Tipo / Range | Dimensione in bytes |
Int8 | ShortInt / -128..127 | 1 |
Int16 | SmallInt / -32768..32767 | 2 |
Int32 | LongInt / -2147483648 .. 2147483647 | 4 |
UInt8 | Byte / 0..255 | 1 |
UInt16 | Word / 0..65535 | 2 |
UInt32 | LongWord / 0..4294967295 | 4 |
DWord | LongWord / 0..4294967295 | 4 |
Cardinal | LongWord / 0..4294967295 | 4 |
UInt64 | QWord / 0 .. 18446744073709551615 | 8 |
Per i numeri con virgola (chiamati “numeri a virgola mobile” o “floating point”) i tipi previsti sono:
Tipo | Range | Dimensione in bytes |
Float | Single o Double o Extended | 4 o 8 o 10 |
Real48 | 2.9E-39 .. 1.7E38 (NOT USE IT !!!!!) | 6 |
Real | Double o Extended | 8 o 10 |
Single | 1.18E-38 .. 3.4E+38 (7 cifre) | 4 |
Double | 2.23E-308 .. 1.79E+308 (15 cifre) | 8 |
Extended | 3.37E-4932 .. 1.18E4932 (19 cifre) o DOUBLE | 10 (o 8 o 16) |
Il tipo FLOAT mantiene la più alta precisione ammissibile dalla CPU / sistema operativo per cui dovrà essere compilato il codice. I calcoli intermedi nelle operazioni complesse vengono mantenuti ed eseguiti con questo formato. Il REAL48 non và usato ed esiste solo per compatibilità con le vecchie versioni del Pascal di Borland. Il tipo EXTENDED invece viene definito come DOUBLE nei sistemi a 64 bit e nelle CPU ARM, mentre negli altri sistemi operativi / CPU la lunghezza del dato potrebbe cambiare.
Un ulteriore tipo numerico esiste di base in Pascal: il CURRENCY, un tipo usato per le operazioni finanziarie con un numero fisso di decimali ossia 4.
Tipo | Range | Dimensione in bytes |
Currency | -922337203685477.5808 .. 922337203685477.5807 | 8 |
Oltre ai tipi interi esistono anche i tipi booleani ovvero variabili che contengono i valori TRUE e FALSE (VERO o FALSO).
Nome | Dimensione in bytes | Valore TRUE/VERO |
Boolean | 1 | 1 |
ByteBool | 1 | Qualsiasi valore diverso da zero |
WordBool | 2 | Qualsiasi valore diverso da zero |
LongBool | 4 | Qualsiasi valore diverso da zero |
Free Pascal e Lazarus comprendono anche il tipo Char che è esattamente un byte di dimensione e contiene uno dei caratteri ASCII (compresi i caratteri estesi). Una costante di tipo carattere quando verrà dichiarata avrà il valore tra virgolette ad esempio ‘A’. Un carattere può anche essere specificato dal suo codice ASCII facendolo precedere dal carattere #. Ad esempio #65 equivale ad ‘A’. Il codice del carattere può valere tra 0 a 255.
ATTENZIONE con i caratteri, ormai da diversi anni le standard ASCII è stato superato (di fatto viene mantenuto solo per numeri e lettere dell’alfabeto inglese più qualche simbolo come il $ o altri). Di norma per contenere i caratteri si usa il tipo String (mantiene più caratteri) in quanto per la rappresentazione di un carattere in tutte le lingue e idiomi del mondo ci potrebbero volere sino a 4 byte (nelle codifiche UTFxx ad esempio). Ad esempio il carattere “è” delle tastiere italiane non può essere rappresentato da un char, se tentate vedrete che il compilatore vi darà errore perché quel carattere è rappresentato da due byte.
Le variabili possono essere suddivise in due macrocategorie: variabili globali e variabili locali. Le variabili globali sono dichiarate nella sezione dichiarativa del programma principale (tra INTERFACE e IMPLEMENTATION) . Hanno visibilità e “vita” per tutta la durata del programma e in tutte le procedure.
Le variabili locali sono dichiarate nella sezione dichiarativa di una procedura/funzione e hanno visibilità e “vita” solo all’interno della procedura in cui sono state dichiarate.
Si possono definire delle variabili globali, ma visibili solo alle procedure e funzioni nell’unità dove vengono dichiarate semplicemente definendole subito dopo la IMPLEMENTATION.
Il programma che abbiamo scritto fino ad adesso usa solo quello locali. Infatti se aggiungete un secondo bottone e fate doppio click su di esso, e successivamente aggiungete il seguente codice otterrete errore in fase di compilazione
procedure TForm1.Button2Click(Sender: TObject);
begin
Memo1.Append('PrimaVariabile : ' + PrimaVariabile);
Memo1.Append('SecondaVariabile: ' + IntToStr(SecondaVariabile));
Memo1.Append('TerzaVariabile : ' + FloatToStr(TerzaVariabile));
Memo1.Append('QuartaVariabile : ' + FloatToStr(QuartaVariabile));
Memo1.Append('QuintaVariabile : ' + QuintaVariabile);
Memo1.Append('Costante : ' + IntToStr(MiaCostante));
end;
Questo perchè il programma non trova le dichiarazioni delle variabili nella Button2Click.
Se volete far vedere una variabile/costante a tutte le procedure/funzioni della form dovete modificare il programma come segue.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
stringa1 : string;
public
end;
var
Form1: TForm1;
const
CostanteGenerica = 'Ciao mondo';
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
PrimaVariabile : char;
SecondaVariabile : integer;
TerzaVariabile, QuartaVariabile : double;
QuintaVariabile : string;
const
MiaCostante = 5;
begin
Memo1.Clear;
PrimaVariabile := 'B';
SecondaVariabile := 0;
SecondaVariabile := SecondaVariabile + 2;
TerzaVariabile := 3.3 + 1;
QuartaVariabile := TerzaVariabile + 1;
QuintaVariabile := 'Ecco a cosa servono le variabili! Fine';
stringa1 := 'pippo';
Memo1.Append('PrimaVariabile : ' + PrimaVariabile);
Memo1.Append('SecondaVariabile: ' + IntToStr(SecondaVariabile));
Memo1.Append('TerzaVariabile : ' + FloatToStr(TerzaVariabile));
Memo1.Append('QuartaVariabile : ' + FloatToStr(QuartaVariabile));
Memo1.Append('QuintaVariabile : ' + QuintaVariabile);
Memo1.Append('Costante : ' + IntToStr(MiaCostante));
Memo1.Append('stringa1 : ' + stringa1);
Memo1.Append('CostanteGenerica: ' + CostanteGenerica);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Memo1.Append('stringa1 : ' + stringa1);
Memo1.Append('CostanteGenerica: ' + CostanteGenerica);
stringa1 := 'pluto';
Memo1.Append('stringa1 : ' + stringa1);
end;
end.
Analizzando il codice noterete la diversa zona di dichiarazione della variabile stringa1 e della costante CostanteGenerica. Ora eseguite il programma e premete prima su button1 e poi su button2. Il risultato dovrebbe essere autoesplicativo.
N.B.: c’è una convenzione che in questo articolo non abbiamo seguito: le costanti vanno scritte tutte maiuscole. Per esempio CostanteGenerica avrebbe dovuto essere COSTANTEGENERICA. Questo per far intuire a qualsiasi lettore del codice che si tratta di una costante e non di una variabile.