Sign in Join
Wiki copytemporary

SizeOf/ru: what changed

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

Title: SizeOf/ru

OldNewLine
1+[[Function/ru|Функция]] [[Compile time|времени компиляции]] [`sizeOf`](https://www.freepascal.org/docs-html/rtl/system/sizeof.html) вычисляет размер в байтах данного имени [[Data type/ru|типа данных]] или [[Identifier/ru|идентификатора]] [[Variable/ru|переменной]].
2+
3+`sizeOf` также может применяться в выражениях времени компиляции внутри [[Compiler directive|директив компилятора]].
4+
5+## Использование
6+
7+`sizeOf` особенно часто встречается в [[Assembler|ассемблере]] или при ручном выделении памяти:
8+
9+``` pascal
10+program sizeOfDemo(input, output, stderr);
11+
12+{$typedAddress on}
13+
14+uses
15+ heaptrc;
16+
17+type
18+ s = record
19+ c: char;
20+ i: longint;
21+ end;
22+
23+var
24+ x: ^s;
25+
26+begin
27+ returnNilIfGrowHeapFails := true;
28+
29+ getMem(x, sizeOf(x));
30+
31+ if not assigned(x) then
32+ begin
33+ writeLn(stderr, 'malloc for x failed');
34+ halt(1);
35+ end;
36+
37+ x^.c := 'r';
38+ x^.i := -42;
39+
40+ freeMem(x, sizeOf(x));
41+end.
42+```
43+
44+Прямая обработка структурированных типов данных на ассемблере также требует знания размеров данных:
45+
46+``` pascal
47+program sizeOfDemo(input, output, stderr);
48+
49+type
50+ integerArray = array of integer;
51+
52+function sum(const f: integerArray): int64;
53+{$ifdef CPUx86_64}
54+assembler;
55+{$asmMode intel}
56+asm
57+ // убеждаемся, что f находится в конкретном регистре
58+ mov rsi, f // rsi := f (указатель на массив)
59+
60+ // проверка на пустой (nil) указатель (напр. пустой массив)
61+ test rsi, rsi // rsi = 0 ?
62+ jz @sum_abort // если rsi = nil, то переходим к @sum_abort
63+
64+ // загружаем последний индекс массива [теоретически это верхний элемент массива F]
65+ mov rcx, [rsi] - sizeOf(sizeInt) // rcx := (rsi - sizeOf(sizeInt))^
66+
67+ // загружаем первый элемент, поскольку условие цикла не дойдет до него
68+ {$if sizeOf(integer) = 4}
69+ mov eax, [rsi] // eax := rsi^
70+ {$elseif sizeOf(integer) = 2}
71+ mov ax, [rsi] // ax := rsi^
72+ {$else} {$error неожиданный целочисленный размер} {$endif}
73+
74+ // мы сделаем, если f не содержит больше элементов
75+ test rcx, rcx // rcx = 0 ?
76+ jz @sum_done // если high(f) = 0, то переходим к @sum_done
77+
78+@sum_iterate:
79+ {$if sizeOf(integer) = 4}
80+ mov edx, [rsi + rcx * 4] // edx := (rsi + 4 * rcx)^
81+ {$elseif sizeOf(integer) = 2}
82+ mov dx, [rsi + rcx * 2] // dx := (rsi + 2 * rcx)^
83+ {$else} {$error неожиданный масштабный коэффициент} {$endif}
84+
85+ add rax, rdx // rax := rax + rdx
86+
87+ jo @sum_abort // если OF, то переходим к @sum_abort
88+
89+ loop @sum_iterate // dec(rcx)
90+ // если rcx <> 0, то переходим к @sum_iterate
91+
92+ jmp @sum_done // переходим к @sum_done
93+
94+@sum_abort:
95+ // загружаем нейтральный элемент для прибавления
96+ xor rax, rax // rax := 0
97+
98+@sum_done:
99+end;
100+{$else}
101+unimplemented;
102+begin
103+ sum := 0;
104+end;
105+{$endif}
106+
107+begin
108+ writeLn(sum(integerArray.create(2, 5, 11, 17, 23)));
109+end.
110+```
111+
112+В [[FPC/ru|FPC]] размер [`integer`](https://www.freepascal.org/docs-html/rtl/system/integer.html) зависит от используемого [[Compiler Mode|режима компилятора]]. Однако `sizeOf(sizeInt)` был вставлен только для демонстрационных целей. В ветке `{$ifdef CPUx86_64}` `sizeOf(sizeInt)` всегда равен `8`.
113+
114+## Сравнительные замечания
115+
116+### Динамические массивы и тому подобное
117+
118+Поскольку [[Dynamic array/ru|динамические массивы]] реализованы как указатели на блок в куче, `sizeOf` оценивает размер указателя. Чтобы определить размер массива - его данных - необходимо использовать `sizeOf` вместе с функцией [`length`](https://www.freepascal.org/docs-html/rtl/system/length.html)
119+
120+``` pascal
121+program dynamicArraySizeDemo(input, output, stderr);
122+
123+uses
124+ sysUtils;
125+
126+resourcestring
127+ enteredN = 'Вы ввели %0:d целых чисел';
128+ totalData = 'занимающих всего %0:d Bytes.';
129+
130+var
131+ f: array of longint;
132+
133+begin
134+ setLength(f, 0);
135+
136+ while not eof() do
137+ begin
138+ setLength(f, length(f) + 1);
139+ readLn(f[length(f)]);
140+ end;
141+
142+ writeLn(format(enteredN, [length(f)]));
143+ writeLn(format(totalData, [length(f) * sizeOf(f[0])]));
144+end.
145+```
146+
147+Подход аналогичен для [[Ansistring|ANSI strings]] (в зависимости от состояния переключателя компилятора `{$longstrings}`, возможно, также обозначаемого [[String/ru|string]]). Не забывайте, что динамические массивы управляют данными перед ссылочным блоком полезной нагрузки. Поэтому, если вы действительно хотите знать, сколько памяти было зарезервировано для одного массива, вам также нужно будет учитывать \[индекс массива\] high (последний индекс в массиве) и счетчик ссылок.
148+
149+### Классы
150+
151+[[Class/ru|Классы]] также являются указателями. Класс [`TObject`](https://www.freepascal.org/docs-html/rtl/system/tobject.html) предоставляет функцию [`instanceSize`](https://www.freepascal.org/docs-html/rtl/system/tobject.instancesize.html). Он возвращает размер объекта, как это предписывается определением типа класса. Дополнительная память, которая выделяется [[Constructor/ru|конструктором]] или любым другим [[Method|методом]], не учитывается. Обратите внимание, что классы также могут содержать динамические массивы или строки ANSI.
152+
153+---
154+*From the Free Pascal wiki, page "SizeOf/ru", 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).*

Back to history