Можно ли получить размер типа, на который указывает указатель в Delphi 7? - PullRequest
1 голос
/ 09 июня 2009

Я хочу получить размер любого типа «запись» в следующей функции. Но, похоже, это не работает:

function GetDataSize(P : Pointer) : Integer;
begin
  Result := SizeOf(P^); // **How to write the code?**
end;

Например, размер следующей записи составляет 8 байт

SampleRecord = record
 Age1 : Integer;
 Age2 : Integer;
end;

Но GetDataSize(@a) всегда возвращает 1 (переменная типа SampleRecord, конечно). Что мне делать?

Я заметил, что в Delphi есть процедура процедура New (var P: Pointer) , которая может выделить блок памяти, соответствует размеру типа, на который указывает P Как он может получить размер?

Ответы [ 4 ]

7 голосов
/ 09 июня 2009

Причина, по которой New знает, сколько памяти выделяется, заключается в том, что New - это магия компилятора . Это встроенный язык, поэтому, когда компилятор видит, что вы его называете, он переписывает его примерно так:

// New(foo);
foo := System._New(SizeOf(foo^), TypeInfo(TypeOf(foo^)));

TypeOf здесь вымышленная функция Delphi для пояснительных целей. Компилятор знает объявленный тип foo, потому что он знает, где находятся все ваши объявления переменных. Вы можете посмотреть на реализацию _New в System.pas . Аналогичная перезапись происходит для Dispose, поэтому он знает, какой тип завершения сделать перед освобождением памяти.

Идеи переменных и объявлений являются понятиями времени компиляции. Во время выполнения они перестают существовать. Во время выполнения указатель - это просто адрес. Тип того, на что он указывает, был определен во время компиляции. Типы определяют размер чего-либо.

Если вам нужно написать функцию, которая принимает указатели на несколько вещей с разными размерами, вам просто нужно предоставить второй параметр , который описывает, на что указывает первый.

Проверьте еще один вопрос здесь: " Как узнать, какой тип является переменной ." Спрашивающий задавался вопросом, как определить дополнительную информацию о переменной, учитывая только ее адрес.

3 голосов
/ 09 июня 2009

Вы не можете найти размер структуры данных, используя переменную типа Pointer, потому что компилятор не может, сделать предположение и проверить его, так как указатель может указывать на любой тип данных, который вы можете себе представить. Вы можете прочитать некоторую информацию здесь .

2 голосов
/ 09 июня 2009

Нет безопасного способа определить размер записи, на которую указывает указатель. Однако, если вы выделили память, на которую указывает указатель, вы можете задать размер этого блока памяти. Но опять же, поскольку вы распределили этот блок, вы уже должны знать размер этого блока! Диспетчер памяти Delphi отслеживает каждый выделенный блок памяти. С информацией из диспетчера памяти можно найти эту информацию, если ваш указатель указывает на начало блока памяти. Однако, если вы выделите большой блок памяти, загрузите в него некоторые данные, и ваш указатель будет указывать на некоторые данные внутри этого блока, этот метод будет весьма ненадежным.

Кроме того, если вы используете ссылочные типы (динамические массивы, строки, классы и т. Д.) В своей записи, размер, который она возвращает, будет по-прежнему непригоден, поскольку вы получите размер ссылки (4 байта) вместо размера данные, на которые ссылаются.

Команда NEW () просто использует информацию о типе типа данных, который вы передаете ему, чтобы получить его размер. Чтобы узнать, как это происходит, вы можете просто проверить исходный код Delphi. Откройте \ source \ Win32 \ rtl \ sys \ System.pas и найдите "_New". (С подчеркиванием перед ним. Использование этого исходного кода может помочь вам понять, как Delphi управляет распределением памяти, хотя исходный код может быть действительно сложным.

0 голосов
/ 09 июня 2009

Delphi имеет встроенный менеджер памяти. Я считаю, что new имеет доступ к объекту кучи и использует HeapSize () (или аналогичные процедуры), чтобы получить размер блока для некоторого указателя.

...