Stałe
Adam Boduch
const - słowo kluczowe języka Delphi
Podobnie jak Zmienne, stałe również służą do przechowywania jakichś danych podczas działania aplikacji. Istnieje jednak pomiędzy nimi istotna różnica. Stałe, jak sama nazwa wskazuje, nie mogą podlegać modyfikacji podczas działania programu. Czyli wartość stałych jest określana już podczas pisania programu:
program varConst;
const
Stala1 = 'Oto jest stała...';
begin
end.
Stałe, w odróżnieniu od zmiennych, deklarujemy z użyciem słowa kluczowego const
(od angielskiego słowa constant - stała). Jak widać, nie musimy deklarować typu stałej. Może on być ustalany na podstawie wartości jaką ma przechowywać.
const
Stala2 = 12;
W ten sposób stała liczbowa, znakowa bądź zbiór może być typu porządkowego i może zostać użyta w instrukcji wielokrotnego wyboru case ... of ...
Programista może samodzielnie określić typ:
program varConst;
const
Stala1 = 'Oto jest stała...';
Stala2 : Byte = 12;
begin
end.
Delphi stara się ustalić jak najmniejszy zakres dla stałej. Patrz Tabela 1 i 2.
Tabela 1. Automatycznie określane typy stało liczbowe.
Wartość | Typ |
---|---|
od -2^63 do - 2.147.483.649 | Int64 |
od -2.147.483.648 do -32.769 | Longint |
od -32.768 do -129 | Smallint |
od -128 do 127 | Shortint |
od 128 do 255 | Byte |
od 256 do 65.535 | Word |
od 65.536 do 2.147.483.647 | Integer |
od 2.147.483.648 do 4.294.967.295 | Cardinal |
od 4.294.967.296 do 2^63-1 | Int64 |
Tabela 2. Inne automatycznie określane typy dla stałych
Wartość | Typ |
---|---|
rzeczywista | Extended |
stała łańcuchowa o dł. 1 | Char |
stała łańcuchowa o dł. > 1 ∧ < 256 | ShortString |
stała łańcuchowa o dł. > 255 | String |
zbiory | zakres wynika bezpośrednio z ich postaci |
const
x = 5;
y = Pred(x); // o ile x nie mam zadeklarowanego typu (jest ordynarne)
z = y + 8; // o ile y nie mam zadeklarowanego typu (jest ordynarne)
q: Byte = Succ(x);
a: Byte = Abs(q); //błąd
var
w: Integer;
begin
case w of
x: {wybrano x};
y: {wybrano y};
z: {wybrano z};
end;
end.
Stałą można definiować za pomocą wyrażenia, pod warunkiem, ze jest ono stałe.
Możliwe jest także użycie tzw. rzutowania, co w praktyce wiąże się z taką deklaracją:
const
Int = Word(342);
W tym przypadku stała Int będzie typu Word o wartości 342. W praktyce jednak takie rzutowanie daje te same rezultaty co sposób określenia typu przedstawiony wcześniej.
W razie próby przypisania jakiejś wartości stałej, przykładowo:
begin
Stala1 := 'Inna wartość';
end.
Delphi uzna to za błąd i wyświetli podpowiedź: [Error] varConst.dpr(8): Left side cannot be assigned to.
Przed chwilą wspomniałem, iż wartości stałych nie podlegają modyfikacji. Istnieje jednak mała ?sztuczka?, która pozwala na zmianę wartości, a polega na ustawieniu odpowiedniej dyrektywy kompilatora.
Dyrektywy kompilatora wyglądają jak zwykłe komentarze. Są one poprzedzane znakiem dolara ($) i umożliwiają zmianę opcji kompilacji. Przykładowo, dyrektywa {$APPTYPE CONSOLE} określa, że aplikacja będzie uruchamiana w oknie konsoli. Kompilator napotykając na taką dyrektywę modyfikuje sposób kompilacji kodu źródłowego.
Umieszczenie w kodzie dyrektywy {$J+} umożliwia modyfikację wartości stałych:
const
{$J+} // wszystkie stałe jakie kompilator napotka od tej pory będą "wartościami".
Stala1 : String = 'Początkowa wartość';
{$J-} // wszystko wraca do normy.
begin
Stala1 := 'Końcowa wartość';
end.
Pochodzi to z czasów świetności Turbo Psacal'a i Delphi 2, w których "stałe" dało się modyfikować tak jak zwykłe zmienne bez użycia dyrektyw. Dlaczego więc projektanci z Borland rozróżnili wtedy "dwa rodzaje" zmiennych? Proponuję spojrzeć na poniższy kod:
procedure Rekurencja;
const
{$J+} i: Byte = 0; {$J-}
begin
if i > 5 then Exit;
Inc(i);
WriteLn(i);
Rekurencja;
end;
begin
Rekurencja;
Rekurencja;
Rekurencja;
ReadLn;
end.
Efekt jest bardzo zabawny. Wygląda na to, ze nasza stała nie jest tak do końca zwykłą zmienną. Zauważamy od razu dwie osobliwości. Pierwsza to to, że i jest wspólna dla wszystkich wywołań procedury (program powinie się zapętlić ze względu na to, że dla każdego wywołania wartość i wynosi 0, co najwyżej 1). Druga to to, że zachowuje swoją wartość mimo zwolnienia z zasobów procedury Rekurencja (biorąc pod uwagę pierwszą osobliwość powinniśmy zobaczyć na ekranie 3x wydruk od 0 do 6).
Ale przechodząc do sedna sprawy. I to nie stała. NIE NALEŻY TEGO NIGDY MYLIĆ. Jest to tzw. zmienna inicjowana. Jest nazywana stałą jedynie ze względy na słowo kluczowe.
Jest możliwość deklarowania stałych tablicowych i rekordowych.
const
//Zwykła stała tablica
arr: array [1..3] of String =
(
'linia #1',
'linia #2',
'linia #3'
);
//Zwykły stały rekord
rec: record
lAnanasow: Integer;
lWinogron: Integer;
lJablek: Integer;
kupujacy: String;
end =
(
lAnanasow: 5;
lWinogron: 20;
lJablek: 3;
kupujacy: 'Pan Kowalski'
);
//stała tablica rekordów
arrRec: array [1..4] of record
liczba: Integer;
ciag: String;
end =
(
(
liczba: 5;
ciag: 'abc';
),
(
liczba: 10; // rekor nie musi być deklarowany w całości
),
(), // rekord nie musi być deklarowany w ogóle
(), // błąd [,] oddziela kolejne elementy
);
Słowo kluczowe const umieszczone w nagłówku procedury lub funkcji oznacza przekazywanie parametru przez wartość. Więcej informacji na temat przekazywania parametrów, znajdziesz w artykule Procedury i funkcje.
Zobacz też:
Hmm... a co mozna jeszcze napisac o stalych tak aby byla to "nowosc"? :)
I uzycie Unicodu nie jest bledem aczkolwiek moze warto by bylo wsopmniec ze jedynie nowsze wersje.
Wszystko pięknie ładnie... w sumie nowości to tu nie ma, ale początkującym się przyda. Natomiast użycie polskich liter w nazwach stałych jest błędem, a nawet jeśli jakieś nowsze Delphi to puści to "Nie jest to jednak często spotykany sposób pracy, można więc potraktować to jako ciekawostkę. " :)