Function/fi
Deutsch · English · Español · Français · Suomi · Русский
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// rax := 0 [false]// examining the assembler output// we can verify x is stored in register rdi [i.e. not rax]// x = 0 ?// if x <> 0 then goto done// rax := 1 [true]// 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.
// 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// r := (@radius+0)^// rax := @result// radius// radius radius// 4 radius radius// pi 4 radius radius// 4*pi radius radius// radius 4*pi radius// radius radius 4*pi radius// radius^2 4*pi radius// 4*pi*radius^2 radius// 4*pi*radius^3// 3 4*pi*radius^3// 4/3*pi*radius^3
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 setYou 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.Katso myös
- § “Using functions and procedures” in the Reference Guide
- § “Intel 80x86 Inline assembler” in the Programmer's Guide
From the Free Pascal wiki, page "Function/fi", as it stood on 2022-08-06 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.
Talk about this page
Nobody has opened a bench for this page yet. Sign in to open one.
