Function/fi
│
Deutsch (de) │
English (en) │
español (es) │
suomi (fi) │
français (fr) │
русский (ru) │
Funktio eli function on rutiini, joka toisin kuin aliohjelma (procedure) palauttaa arvon. Funktion kutsu käytännössä korvautuu sen palautusarvolla. Jos {$extendedSyntax}
kääntäjän kytkin (compiler switch) on pois päältä,
funktion kutsu ei voi esiintyä ei-tuottavina lauseina, vaan niiden on oltava osa lauseketta.
Sana function
on varattu sana.
Palautusarvo
Normaalin aliohjelman esittelyn lisäksi funktion esittely sisältää myös palautustyypin: muodollisen parametriluettelon jälkeen tulee kaksoispiste- ja palautustyyppi.
Seuraava funktion esittely palauttaa esimerkiksi boolean
tyyppisen arvon.
function myFunction(const firstParameter: real): boolean;
Funktion toteuttamisessa on useita tapoja toteuttaa funktion palautusarvo.
program functionDemo(input, output, stderr);
{$mode objfpc}
// Perinteinen tapa:
// palautus arvo tallennetaan muuttujaan
// jonka nimi on sama kuin funktion nimi
function myLine(const x: real): real;
begin
myLine := 0.5 * x + 2;
end;
Jos {$modeswitch result+}
on käytössä. Se asetetaan {$mode objFPC}
ja {$mode Delphi}
,
niin toteutuslohkon sisällä on käytössä tunniste result
myöskin:
// käytetään `result` tunnistetta
function myParabola(const x: real): real;
begin
result := sqr(x) - 1;
end;
Lisäksi {$mode objFPC}
:ssa rutiini
exit
asettaa myös palautusarvon ja jättää pinoon kehyksen.
Kahdessa aikaisemmassa esimerkissä olisi voinut esiintyä muita lausekkeita ja ne olisi toteutettu, kun taas
exit
:n jälkeen palataan funktiosta pois.
Tämä on samanlainen käyttäytyminen kuin C:n tai joidenkin muiden ohjelmointikielien return
lausekkeen käyttäytyminen.
// käytetään exit rutiinia
function even(const x: longint): boolean;
begin
exit(not odd(x));
end;
Assembly kielen yhteydessä sovelletaan muita sääntöjä. Jos palautustyyppi on kiinteä arvo, käytetään akku-rekisteriä, jos se mahtuu sinne:
// in assembly language:
// return type fits into a single register => use accumulator register
function zero(const x: int64): boolean;
{$ifdef CPUx86_64}
assembler; register;
{$asmMode intel}
asm
// xor modifies flags => put it in front of test
xor rax, rax // rax := 0 [false]
// examining the assembler output
// we can verify x is stored in register rdi [i.e. not rax]
test x, x // x = 0 ?
jnz @zero_done // if x <> 0 then goto done
inc rax // rax := 1 [true]
@zero_done:
// When you examine the assembler output
// you will notice the compiler automatically inserts code
// that moves the contents of rax to the right spot on the stack.
end;
{$else}
begin
// NOTE: with optimization switches enabled
// the compiler produces with the following Pascal statement
// even shorter (and maybe faster) code
// than the assembler implementation above
result := x = 0;
end;
{$endif}
Muuten riippuen siitä, mikä {$asmMode}
on aktiivinen, @result
(Intel) tai __result
(AT&T) -makroa voidaan käyttää.
type
bodyAttributes = record
surfaceArea: real;
volume: real;
end;
// in assembly language:
// return type doesn't fit into accumulator => @result macro gives address
function sphere(const radius: real): bodyAttributes;
{$ifdef CPUx86_64}
assembler;
{$asmMode intel}
const
three: longint = 3;
four: longint = 4;
var
r: real;
asm
pextrq r, radius, 0 // r := (@radius+0)^
lea rax, @result // rax := @result
fld r // radius
fld st(0) // radius radius
fild four // 4 radius radius
fldpi // pi 4 radius radius
fmul // 4*pi radius radius
fxch // radius 4*pi radius
fld st(0) // radius radius 4*pi radius
fmul // radius^2 4*pi radius
fmul // 4*pi*radius^2 radius
fst [rax].bodyAttributes.surfaceArea
fmul // 4*pi*radius^3
fild three // 3 4*pi*radius^3
fdivp // 4/3*pi*radius^3
fst [rax].bodyAttributes.volume
end;
{$else}
begin
sphere.surfaceArea := 4 * pi() * sqr(radius);
sphere.volume := 4 / 3 * pi() * sqr(radius) * abs(radius);
end;
{$endif}
Alun perin Pascal odotti täsmällisesti yhden tehtävän tulosmuuttujalle. FPC ei kuitenkaan kiellä käyttämästä useita. Se lähettää varoituksen, jos mikään mahdollisista palautumisarvoista ei ole käytössä tai poistumisrutiinia ei ole kirjoitettu.
- Warning
- Function result does not seem to be set
- You can get this warning if the compiler thinks that a function return value is not set. This will not be displayed for assembler procedures, or procedures that contain assembler blocks.
begin
writeLn(sphere(2.0).surfaceArea);
end.