Function/fi: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: Function/fi
| Old | New | Line | |
|---|---|---|---|
| 1 | + | Funktio eli **function** on [[Routine/fi|rutiini]], joka toisin kuin [[Procedure/fi|aliohjelma (procedure)]] palauttaa arvon. Funktion kutsu käytännössä korvautuu sen palautusarvolla. Jos [[sExtendedsyntax|{$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. | |
| 2 | + | ||
| 3 | + | Sana `function` on [[Reserved word/fi|varattu sana]]. | |
| 4 | + | ||
| 5 | + | ## Palautusarvo | |
| 6 | + | ||
| 7 | + | Normaalin aliohjelman esittelyn lisäksi funktion esittely sisältää myös [[Data type/fi|palautustyypin]]: muodollisen parametriluettelon jälkeen tulee [[Colon/fi|kaksoispiste-]] ja palautustyyppi. Seuraava funktion esittely palauttaa esimerkiksi [[Boolean/fi|boolean]] tyyppisen arvon. | |
| 8 | + | ||
| 9 | + | ``` pascal | |
| 10 | + | function myFunction(const firstParameter: real): boolean; | |
| 11 | + | ``` | |
| 12 | + | ||
| 13 | + | Funktion toteuttamisessa on useita tapoja toteuttaa funktion palautusarvo. | |
| 14 | + | ||
| 15 | + | ``` pascal | |
| 16 | + | program functionDemo(input, output, stderr); | |
| 17 | + | ||
| 18 | + | {$mode objfpc} | |
| 19 | + | ||
| 20 | + | // Perinteinen tapa: | |
| 21 | + | // palautus arvo tallennetaan muuttujaan | |
| 22 | + | // jonka nimi on sama kuin funktion nimi | |
| 23 | + | function myLine(const x: real): real; | |
| 24 | + | begin | |
| 25 | + | myLine := 0.5 * x + 2; | |
| 26 | + | end; | |
| 27 | + | ``` | |
| 28 | + | ||
| 29 | + | Jos `{$modeswitch result+}` on käytössä. Se asetetaan [[Mode ObjFPC|{$mode objFPC}]] ja [[Mode Delphi|{$mode Delphi}]], niin toteutuslohkon sisällä on käytössä [[Identifier/fi|tunniste]] `result` myöskin: | |
| 30 | + | ||
| 31 | + | ``` pascal | |
| 32 | + | // käytetään `result` tunnistetta | |
| 33 | + | function myParabola(const x: real): real; | |
| 34 | + | begin | |
| 35 | + | result := sqr(x) - 1; | |
| 36 | + | end; | |
| 37 | + | ``` | |
| 38 | + | ||
| 39 | + | Lisäksi `{$mode objFPC}`:ssa rutiini [`exit`](https://www.freepascal.org/docs-html/rtl/system/exit.html) 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. | |
| 40 | + | ||
| 41 | + | ``` pascal | |
| 42 | + | // käytetään exit rutiinia | |
| 43 | + | function even(const x: longint): boolean; | |
| 44 | + | begin | |
| 45 | + | exit(not odd(x)); | |
| 46 | + | end; | |
| 47 | + | ``` | |
| 48 | + | ||
| 49 | + | [[Assembly language/fi|Assembly kielen]] yhteydessä sovelletaan muita sääntöjä. Jos palautustyyppi on kiinteä arvo, käytetään akku-rekisteriä, jos se mahtuu sinne: | |
| 50 | + | ||
| 51 | + | ``` pascal | |
| 52 | + | // in assembly language: | |
| 53 | + | // return type fits into a single register => use accumulator register | |
| 54 | + | function zero(const x: int64): boolean; | |
| 55 | + | {$ifdef CPUx86_64} | |
| 56 | + | assembler; register; | |
| 57 | + | {$asmMode intel} | |
| 58 | + | asm | |
| 59 | + | // xor modifies flags => put it in front of test | |
| 60 | + | xor rax, rax // rax := 0 [false] | |
| 61 | + | ||
| 62 | + | // examining the assembler output | |
| 63 | + | // we can verify x is stored in register rdi [i.e. not rax] | |
| 64 | + | test x, x // x = 0 ? | |
| 65 | + | jnz @zero_done // if x <> 0 then goto done | |
| 66 | + | ||
| 67 | + | inc rax // rax := 1 [true] | |
| 68 | + | @zero_done: | |
| 69 | + | // When you examine the assembler output | |
| 70 | + | // you will notice the compiler automatically inserts code | |
| 71 | + | // that moves the contents of rax to the right spot on the stack. | |
| 72 | + | end; | |
| 73 | + | {$else} | |
| 74 | + | begin | |
| 75 | + | // NOTE: with optimization switches enabled | |
| 76 | + | // the compiler produces with the following Pascal statement | |
| 77 | + | // even shorter (and maybe faster) code | |
| 78 | + | // than the assembler implementation above | |
| 79 | + | result := x = 0; | |
| 80 | + | end; | |
| 81 | + | {$endif} | |
| 82 | + | ``` | |
| 83 | + | ||
| 84 | + | Muuten riippuen siitä, mikä [[sAsmmode|{$asmMode}]] on aktiivinen, `@result` (Intel) tai `__result` (AT&T) -makroa voidaan käyttää. | |
| 85 | + | ||
| 86 | + | ``` pascal | |
| 87 | + | type | |
| 88 | + | bodyAttributes = record | |
| 89 | + | surfaceArea: real; | |
| 90 | + | volume: real; | |
| 91 | + | end; | |
| 92 | + | ||
| 93 | + | // in assembly language: | |
| 94 | + | // return type doesn't fit into accumulator => @result macro gives address | |
| 95 | + | function sphere(const radius: real): bodyAttributes; | |
| 96 | + | {$ifdef CPUx86_64} | |
| 97 | + | assembler; | |
| 98 | + | {$asmMode intel} | |
| 99 | + | const | |
| 100 | + | three: longint = 3; | |
| 101 | + | four: longint = 4; | |
| 102 | + | var | |
| 103 | + | r: real; | |
| 104 | + | asm | |
| 105 | + | pextrq r, radius, 0 // r := (@radius+0)^ | |
| 106 | + | lea rax, @result // rax := @result | |
| 107 | + | fld r // radius | |
| 108 | + | ||
| 109 | + | fld st(0) // radius radius | |
| 110 | + | fild four // 4 radius radius | |
| 111 | + | fldpi // pi 4 radius radius | |
| 112 | + | fmul // 4*pi radius radius | |
| 113 | + | fxch // radius 4*pi radius | |
| 114 | + | fld st(0) // radius radius 4*pi radius | |
| 115 | + | fmul // radius^2 4*pi radius | |
| 116 | + | fmul // 4*pi*radius^2 radius | |
| 117 | + | fst [rax].bodyAttributes.surfaceArea | |
| 118 | + | ||
| 119 | + | fmul // 4*pi*radius^3 | |
| 120 | + | fild three // 3 4*pi*radius^3 | |
| 121 | + | fdivp // 4/3*pi*radius^3 | |
| 122 | + | fst [rax].bodyAttributes.volume | |
| 123 | + | end; | |
| 124 | + | {$else} | |
| 125 | + | begin | |
| 126 | + | sphere.surfaceArea := 4 * pi() * sqr(radius); | |
| 127 | + | sphere.volume := 4 / 3 * pi() * sqr(radius) * abs(radius); | |
| 128 | + | end; | |
| 129 | + | {$endif} | |
| 130 | + | ``` | |
| 131 | + | ||
| 132 | + | 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. | |
| 133 | + | ||
| 134 | + | > Warning | |
| 135 | + | > Function result does not seem to be set | |
| 136 | + | > | |
| 137 | + | > 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. | |
| 138 | + | ||
| 139 | + | ``` pascal | |
| 140 | + | begin | |
| 141 | + | writeLn(sphere(2.0).surfaceArea); | |
| 142 | + | end. | |
| 143 | + | ``` | |
| 144 | + | ||
| 145 | + | ## Katso myös | |
| 146 | + | ||
| 147 | + | - [§ “Using functions and procedures” in the Reference Guide](https://www.freepascal.org/docs-html/ref/refch14.html) | |
| 148 | + | - [§ “Intel 80x86 Inline assembler” in the Programmer's Guide](https://www.freepascal.org/docs-html/prog/progse10.html) | |
| 149 | + | ||
| 150 | + | --- | |
| 151 | + | *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](/wiki-contact).* |
