Копия викизеркало

Это зеркало вики с pascal.chat. Правка, история и вход — там.

SizeOf/ru

Deutsch · English · Suomi · Русский

Функция времени компиляции sizeOf вычисляет размер в байтах данного имени типа данных или идентификатора переменной.

sizeOf также может применяться в выражениях времени компиляции внутри директив компилятора.

Использование

sizeOf особенно часто встречается в ассемблере или при ручном выделении памяти:

pascal
program sizeOfDemo(input, output, stderr);

{$typedAddress on}

uses
    heaptrc;

type
    s = record
        c: char;
        i: longint;
    end;

var
    x: ^s;

begin
    returnNilIfGrowHeapFails := true;
    
    getMem(x, sizeOf(x));
    
    if not assigned(x) then
    begin
        writeLn(stderr, 'malloc for x failed');
        halt(1);
    end;
    
    x^.c := 'r';
    x^.i := -42;
    
    freeMem(x, sizeOf(x));
end.

Прямая обработка структурированных типов данных на ассемблере также требует знания размеров данных:

pascal
program sizeOfDemo(input, output, stderr);

type
    integerArray = array of integer;

function sum(const f: integerArray): int64;
{$ifdef CPUx86_64}
assembler;
{$asmMode intel}
asm// убеждаемся, что f находится в конкретном регистре// rsi := f  (указатель на массив)// проверка на пустой (nil) указатель (напр. пустой массив)// rsi = 0 ?// если rsi = nil, то переходим к @sum_abort// загружаем последний индекс массива [теоретически это верхний элемент массива F]// rcx := (rsi - sizeOf(sizeInt))^// загружаем первый элемент, поскольку условие цикла не дойдет до него{$if sizeOf(integer) = 4}// eax := rsi^{$elseif sizeOf(integer) = 2}// ax := rsi^{$else}{$error неожиданный целочисленный размер}{$endif}// мы сделаем, если f не содержит больше элементов// rcx = 0 ?// если high(f) = 0,  то переходим к @sum_done{$if sizeOf(integer) = 4}// edx := (rsi + 4 * rcx)^{$elseif sizeOf(integer) = 2}// dx := (rsi + 2 * rcx)^{$else}{$error неожиданный масштабный коэффициент}{$endif}// rax := rax + rdx// если OF, то переходим к @sum_abort// dec(rcx)// если rcx <> 0,  то переходим к @sum_iterate// переходим к @sum_done// загружаем нейтральный элемент для прибавления// rax := 0
    // убеждаемся, что f находится в конкретном регистре
    mov rsi, f                       // rsi := f  (указатель на массив)
    
    // проверка на пустой (nil) указатель (напр. пустой массив)
    test rsi, rsi                    // rsi = 0 ?
    jz @sum_abort                    // если rsi = nil, то переходим к @sum_abort
    
    // загружаем последний индекс массива [теоретически это верхний элемент массива F]
    mov rcx, [rsi] - sizeOf(sizeInt) // rcx := (rsi - sizeOf(sizeInt))^
    
    // загружаем первый элемент, поскольку условие цикла не дойдет до него
    {$if sizeOf(integer) = 4}
    mov eax, [rsi]                   // eax := rsi^
    {$elseif sizeOf(integer) = 2}
    mov ax, [rsi]                    // ax := rsi^
    {$else} {$error неожиданный целочисленный размер} {$endif}
    
    // мы сделаем, если f не содержит больше элементов
    test rcx, rcx                    // rcx = 0 ?
    jz @sum_done                     // если high(f) = 0,  то переходим к @sum_done
    
@sum_iterate:
    {$if sizeOf(integer) = 4}
    mov edx, [rsi + rcx * 4]         // edx := (rsi + 4 * rcx)^
    {$elseif sizeOf(integer) = 2}
    mov dx, [rsi + rcx * 2]          // dx := (rsi + 2 * rcx)^
    {$else} {$error неожиданный масштабный коэффициент} {$endif}
    
    add rax, rdx                     // rax := rax + rdx
    
    jo @sum_abort                    // если OF, то переходим к @sum_abort
    
    loop @sum_iterate                // dec(rcx)
                                     // если rcx <> 0,  то переходим к @sum_iterate
    
    jmp @sum_done                    // переходим к @sum_done
    
@sum_abort:
    // загружаем нейтральный элемент для прибавления
    xor rax, rax                     // rax := 0
    
@sum_done:
END;
{$else}
unimplemented;
begin
    sum := 0;
end;
{$endif}

begin
    writeLn(sum(integerArray.create(2, 5, 11, 17, 23)));
end.

В FPC размер integer зависит от используемого режима компилятора. Однако sizeOf(sizeInt) был вставлен только для демонстрационных целей. В ветке {$ifdef CPUx86_64} sizeOf(sizeInt) всегда равен 8.

Сравнительные замечания

Динамические массивы и тому подобное

Поскольку динамические массивы реализованы как указатели на блок в куче, sizeOf оценивает размер указателя. Чтобы определить размер массива - его данных - необходимо использовать sizeOf вместе с функцией length

pascal
program dynamicArraySizeDemo(input, output, stderr);

uses
    sysUtils;

resourcestring
    enteredN = 'Вы ввели %0:d целых чисел';
    totalData = 'занимающих всего %0:d Bytes.';

var
    f: array of longint;

begin
    setLength(f, 0);
    
    while not eof() do
    begin
        setLength(f, length(f) + 1);
        readLn(f[length(f)]);
    end;
    
    writeLn(format(enteredN, [length(f)]));
    writeLn(format(totalData, [length(f) * sizeOf(f[0])]));
end.

Подход аналогичен для ANSI strings (в зависимости от состояния переключателя компилятора {$longstrings}, возможно, также обозначаемого string). Не забывайте, что динамические массивы управляют данными перед ссылочным блоком полезной нагрузки. Поэтому, если вы действительно хотите знать, сколько памяти было зарезервировано для одного массива, вам также нужно будет учитывать [индекс массива] high (последний индекс в массиве) и счетчик ссылок.

Классы

Классы также являются указателями. Класс TObject предоставляет функцию instanceSize. Он возвращает размер объекта, как это предписывается определением типа класса. Дополнительная память, которая выделяется конструктором или любым другим методом, не учитывается. Обратите внимание, что классы также могут содержать динамические массивы или строки ANSI.


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.

Версия 1, последнее изменение: WikiArchive, .