Sign in Join
Wiki copytemporary

Function/ru: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Function/ru

OldNewLine
1+**Функция** — это [[Routine|подпрограмма]], которая, в отличие от [[Procedure|процедур]], возвращает значение. Вызов функции практически заменяется возвращаемым значением. Если состояние переключателя компилятора [[$extendedSyntax|{$extendedSyntax}]] отключено, вызовы функций не могут отображаться как непродуктивные операторы, но должны быть целиком или частью [[expression|выражения]].
2+
3+Слово `function` является [[Reserved word|зарезервированным словом]].
4+
5+## Возвращаемое значение
6+
7+В дополнение к обычной процедуре формальная сигнатура функции содержит [[Data type/ru|тип]] возвращаемого значения: список формальных параметров должен сопровождаться [[Colon|двоеточием]] и типом возвращаемого значения. Например, следующая функция возвращает [[Boolean]]
8+
9+``` pascal
10+function myFunction(const firstParameter: real): Boolean;
11+```
12+
13+При реализации функций есть несколько способов определить возвращаемое значение функции.
14+
15+``` pascal
16+program functionDemo(input, output, stderr);
17+
18+{$mode objFPC}
19+
20+// традиционный синтаксис:
21+// результат сохраняется в переменной
22+// его имя такое же, как у функции
23+function myLine(const x: real): real;
24+begin
25+ myLine := 0.5 * x + 2;
26+end;
27+```
28+
29+Если `{$modeswitch result+}`, заданный [[Mode ObjFPC|{$mode objFPC}]] и [[Mode Delphi|{$mode Delphi}]], внутри блока реализации также доступен результат специального идентификатора:
30+
31+``` pascal
32+// используя специальный идентификатор `result`
33+function myParabola(const x: real): real;
34+begin
35+ result := sqr(x) - 1;
36+end;
37+```
38+
39+Кроме того, в `{$mode objFPC}` подпрограмма [`exit`](https://www.freepascal.org/docs-html/rtl/system/exit.html) также установит возвращаемое значение *и* покинет стековый кадр. В предыдущих двух примерах могли появиться дополнительные операторы, и они были бы выполнены, уже после того, как `exit` подпрограмма *выполнится*. Это поведение оператора `return` в C или других языках программирования.
40+
41+``` pascal
42+// использование процедуры выхода exit
43+function even(const x: longint): Boolean;
44+begin
45+ exit(not odd(x));
46+end;
47+```
48+
49+В языке [[Assembly language|ассемблера]] применяются другие правила. Если тип возвращаемого значения является целым числом, используется регистр-накопитель, при условии, что он помещается туда:
50+
51+``` pascal
52+// на ассемблере:
53+// возвращаемый тип умещается в один регистр => использовать регистр-накопитель
54+function zero(const x: int64): Boolean;
55+{$ifDef CPUx86_64}
56+assembler; register;
57+{$asmMode intel}
58+asm
59+ // xor изменяет флаги => поместите его перед тестом
60+ xor rax, rax // rax := 0 (удалить остаток)
61+
62+ test x, x // x = 0 ?
63+ setz al // rax := ZF
64+
65+ // Когда вы изучаете вывод ассемблера
66+ // вы заметите, что компилятор автоматически вставляет код
67+ // который перемещает содержимое rax в нужное место в стеке,
68+ // пока не появится подсказка noStackFrame
69+ // (автоматически устанавливается некоторыми уровнями оптимизации)
70+ // инструктирует компилятор опустить кадр стека, если это возможно.
71+end;
72+{$else}
73+begin
74+ result := x = 0;
75+end;
76+{$endIf}
77+```
78+
79+В противном случае, в зависимости от того, какой режим [[sAsmmode|{$asmMode}]] активен, можно использовать макрос `@result` (Intel) или `__result` (AT&T).
80+
81+``` pascal
82+type
83+ bodyAttributes = record
84+ surfaceArea: real;
85+ volume: real;
86+ end;
87+
88+// на ассемблере:
89+// возвращаемый тип не помещается в аккумулятор => макрос @result дает адрес
90+function sphere(const radius: real): bodyAttributes;
91+{$ifDef CPUx86_64}
92+assembler;
93+{$asmMode intel}
94+const
95+ three: longint = 3;
96+ four: longint = 4;
97+var
98+ r: real;
99+asm
100+ pextrq r, radius, 0 // r := (@radius+0)^
101+ lea rax, @result // rax := @result
102+ fld r // radius
103+
104+ fld st(0) // radius radius
105+ fild four // 4 radius radius
106+ fldpi // pi 4 radius radius
107+ fmul // 4*pi radius radius
108+ fxch // radius 4*pi radius
109+ fld st(0) // radius radius 4*pi radius
110+ fmul // radius^2 4*pi radius
111+ fmul // 4*pi*radius^2 radius
112+ fst [rax].bodyAttributes.surfaceArea
113+
114+ fmul // 4*pi*radius^3
115+ fild three // 3 4*pi*radius^3
116+ fdivp // 4/3*pi*radius^3
117+ fst [rax].bodyAttributes.volume
118+end;
119+{$else}
120+begin
121+ sphere.surfaceArea := 4 * pi() * sqr(radius);
122+ sphere.volume := 4 / 3 * pi() * sqr(radius) * abs(radius);
123+end;
124+{$endIf}
125+```
126+
127+Первоначально Паскаль ожидал *ровно одно* [[Becomes|присваивание]] переменной результата (в зависимости от того, что используется). Однако [[FPC]] не запрещает множественные присваивания. Он выдаст предупреждение, если не был использован ни один из возможных идентификаторов результата или процедура выхода не написана.
128+
129+> Warning
130+> Function result does not seem to be set (*рус*. Предупреждение: результат функции, похоже, не установлен)
131+>
132+> You can get this warning if the [[Compiler|compiler]] thinks that a function return value is not set. This will not be displayed for assembler procedures, or procedures that contain assembler blocks.(*рус*. Вы можете получить это предупреждение, если [[Compiler|компилятор]] считает, что возвращаемое значение функции не установлено. Это не будет отображаться для ассемблерных процедур или процедур, содержащих ассемблерные блоки.)
133+
134+``` pascal
135+begin
136+ writeLn(sphere(2.0).surfaceArea);
137+end.
138+```
139+
140+Обратите внимание, что в случае [[Operator overloading|перегрузок операторов]] в формальной подписи должен быть объявлен специальный вид функции, идентификатор переменной результата. Подробнее см. в статье.
141+
142+## Замечания
143+
144+[[Pure functions]] это функции, не зависящие от внешнего состояния.
145+
146+## См.также
147+
148+- [[Pascal basics]]
149+- [§ “Using functions and procedures” in the Reference Guide](https://www.freepascal.org/docs-html/ref/refch14.html)
150+- [§ “Intel 80x86 Inline assembler” in the Programmer’s Guide](https://www.freepascal.org/docs-html/prog/progse10.html)
151+
152+---
153+*From the Free Pascal wiki, page "Function/ru", as it stood on 2022-05-31 after a change by Zoltanleo, 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).*

Back to history