Function
│
Deutsch (de) │
English (en) │
español (es) │
suomi (fi) │
français (fr) │
русский (ru) │
A function is a routine that, in contrast to procedures, returns a value.
A call of a function is virtually substituted by its return value.
If the {$extendedSyntax}
compiler switch state is off, function calls can not appear as non-productive statements, but have to be or be part of an expression.
The word function
is a reserved word.
Return value
In addition to a normal procedure, a function's formal signature contains a return type:
The formal parameter list has to be succeeded by a colon and return type.
For instance the following function returns a boolean
.
function myFunction(const firstParameter: real): boolean;
When implementing functions there are several ways to define the function's return value.
1program functionDemo(input, output, stderr);
2
3{$mode objFPC}
4
5// traditional syntax:
6// the result is stored in the variable
7// its name is the same as the function's
8function myLine(const x: real): real;
9begin
10 myLine := 0.5 * x + 2;
11end;
If {$modeswitch result+}
, which is set by {$mode objFPC}
and {$mode Delphi}
, inside the implementation block the special identifier result
is available, too:
13// using special `result` identifier
14function myParabola(const x: real): real;
15begin
16 result := sqr(x) - 1;
17end;
Additionally, in {$mode objFPC}
the routine exit
will set the return value, too, and leave the stack frame.
In the previous two examples further statements could have appeared, and they would have been executed, whilst after an exit
the routine is done.
This is the behavior a return
statement in C or other programming languages has.
19// using exit routine
20function even(const x: longint): boolean;
21begin
22 exit(not odd(x));
23end;
In assembly language other rules apply. If the return type is an integral value, the accumulator register is used, provided it fits in there:
25// in assembly language:
26// return type fits into a single register => use accumulator register
27function zero(const x: int64): boolean;
28{$ifDef CPUx86_64}
29assembler; register;
30{$asmMode intel}
31asm
32 // xor modifies flags => put it in front of test
33 xor rax, rax // rax := 0 (remove residue)
34
35 test x, x // x = 0 ?
36 setz al // rax := ZF
37
38 // When you examine the assembler output
39 // you will notice the compiler automatically inserts code
40 // that moves the contents of rax to the right spot on the stack,
41 // unless the noStackFrame hint
42 // (automatically set by some optimization levels)
43 // instructs the compiler to omit the stack frame if possible.
44end;
45{$else}
46begin
47 result := x = 0;
48end;
49{$endIf}
Otherwise, depending on which {$asmMode}
is active, the @result
(Intel) or __result
(AT&T) macro can be used.
51type
52 bodyAttributes = record
53 surfaceArea: real;
54 volume: real;
55 end;
56
57// in assembly language:
58// return type doesn't fit into accumulator => @result macro gives address
59function sphere(const radius: real): bodyAttributes;
60{$ifDef CPUx86_64}
61assembler;
62{$asmMode intel}
63const
64 three: longint = 3;
65 four: longint = 4;
66var
67 r: real;
68asm
69 pextrq r, radius, 0 // r := (@radius+0)^
70 lea rax, @result // rax := @result
71 fld r // radius
72
73 fld st(0) // radius radius
74 fild four // 4 radius radius
75 fldpi // pi 4 radius radius
76 fmul // 4*pi radius radius
77 fxch // radius 4*pi radius
78 fld st(0) // radius radius 4*pi radius
79 fmul // radius^2 4*pi radius
80 fmul // 4*pi*radius^2 radius
81 fst [rax].bodyAttributes.surfaceArea
82
83 fmul // 4*pi*radius^3
84 fild three // 3 4*pi*radius^3
85 fdivp // 4/3*pi*radius^3
86 fst [rax].bodyAttributes.volume
87end;
88{$else}
89begin
90 sphere.surfaceArea := 4 * pi() * sqr(radius);
91 sphere.volume := 4 / 3 * pi() * sqr(radius) * abs(radius);
92end;
93{$endIf}
Originally Pascal expected exact one assignment to the result variable (whichever is used). FPC however does not prohibit multiple assignments. It will emit a warning if none of the possible result identifiers were used or the exit routine is not written.
- 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.
95begin
96 writeLn(sphere(2.0).surfaceArea);
97end.