номер
Во-первых, не существует такой вещи, как "неинстанцированная переменная". Вы создаете его, просто вводя его имя и вводя в исходный файл.
Во-вторых, вы уже знаете все, что нужно знать о переменной, посмотрев на нее в своем исходном коде. Переменная перестает существовать после компиляции вашей программы. После этого это всего лишь биты.
Указатель имеет тип только во время компиляции. Во время выполнения все, что можно сделать по этому адресу, уже определено. Компилятор проверяет это, как вы уже заметили. Проверка типа переменной во время выполнения полезна только в языках, где тип переменной может измениться, как в динамических языках. Наиболее близкий Delphi к этому типу Variant
. Тип переменной всегда Variant
, но вы можете хранить в ней много типов значений. Чтобы выяснить, что он содержит, вы можете использовать функцию VarType
.
В любое время, когда вы захотите использовать TypeInfo
для получения информации о типе типа, связанного с переменной, вы также можете напрямую назвать интересующий вас тип; если переменная находится в области видимости, вы можете найти ее объявление и использовать объявленный тип при вызове TypeInfo
.
Если вы хотите передать произвольный адрес функции и заставить эту функцию обнаруживать информацию о типе для себя, вам не повезло. Вместо этого вам нужно будет передать значение PTypeInfo
в качестве дополнительного параметра. Это то, что делают все встроенные функции Delphi. Например, когда вы вызываете New
для переменной указателя, компилятор вставляет дополнительный параметр, который содержит значение PTypeInfo
для типа, который вы выделяете. Когда вы вызываете SetLength
для динамического массива, компилятор вставляет значение PTypeInfo
для типа массива.
Ответ, который вы дали , предполагает, что вы ищете что-то, кроме того, о чем вы просили. Учитывая ваш вопрос, я подумал, что вы искали гипотетическую функцию, которая могла бы удовлетворить этот код:
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= GetVariableTypeInfo(@S);
Assert(Info = TypeInfo(string));
Info:= GetVariableTypeInfo(@Instance);
Assert(Info = TypeInfo(IObjectType));
Info:= GetVariableTypeInfo(@Obj);
Assert(Info = TypeInfo(TDBGrid));
end;
Давайте используем функции IsClass
и IsObject
из JCL для построения этой функции:
function GetVariableTypeInfo(pvar: Pointer): PTypeInfo;
begin
if not Assigned(pvar) then
Result := nil
else if IsClass(PPointer(pvar)^) then
Result := PClass(pvar).ClassInfo
else if IsObject(PPointer(pvar)^) then
Result := PObject(pvar).ClassInfo
else
raise EUnknownResult.Create;
end;
Очевидно, он не будет работать для S
или Instance
и выше, но давайте посмотрим, что происходит с Obj
:
Info := GetVariableTypeInfo(@Obj);
Это должно привести к нарушению доступа. Obj
не имеет значения, поэтому IsClass
и IsObject
оба будут читать неопределенный адрес памяти, вероятно, не тот, который принадлежит вашему процессу. Вы запросили подпрограмму, в которой в качестве входных данных использовался бы адрес переменной, но простого адреса недостаточно.
Теперь давайте подробнее рассмотрим, как на самом деле ведут себя IsClass
и IsObject
. Эти функции принимают произвольное значение и проверяют, выглядит ли значение как , может ли это быть значение данного типа, либо объект (экземпляр), либо класс. Используйте это так:
// This code will yield no assertion failures.
var
p: Pointer;
o: TObject;
a: array of Integer;
begin
p := TDBGrid;
Assert(IsClass(p));
p := TForm.Create(nil);
Assert(IsObject(p));
// So far, so good. Works just as expected.
// Now things get interesting:
Pointer(a) := p;
Assert(IsObject(a));
Pointer(a) := nil;
// A dynamic array is an object? Hmm.
o := nil;
try
IsObject(o);
Assert(False);
except
on e: TObject do
Assert(e is EAccessViolation);
end;
// The variable is clearly a TObject, but since it
// doesn't hold a reference to an object, IsObject
// can't check whether its class field looks like
// a valid class reference.
end;
Обратите внимание, что функции ничего не сообщают о переменных, только о значениях , которые они содержат. Поэтому я бы не стал рассматривать эти функции, чтобы ответить на вопрос, как получить информацию о типе переменной.
Кроме того, вы сказали, что все, что вы знаете о переменной, это ее адрес. Найденные вами функции не принимают адрес переменной. Они принимают значение переменной. Вот демонстрация:
var
c: TClass;
begin
c := TDBGrid;
Assert(IsClass(c));
Assert(not IsClass(@c)); // Address of variable
Assert(IsObject(@c)); // Address of variable is an object?
end;
Вы можете возразить против того, как я злоупотребляю этими функциями, передав в них то, что очевидно является мусором. Но я думаю, что это only , так что имеет смысл поговорить на эту тему. Если вы знаете, что у вас никогда не будет значений мусора, то вам все равно не нужна запрашиваемая вами функция, потому что вы уже достаточно знаете о своей программе, чтобы использовать реальные типы для ваших переменных.
В целом, вы задаете не тот вопрос. Вместо того, чтобы спрашивать, как вы определяете тип переменной или тип значения в памяти, вы должны спрашивать, как вы оказались в положении, когда вы еще не знаете типы ваших переменных и ваших данных .