Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>No.</p> <p>First, there's no such thing as a "non-instantiated variable." You instantiate it by the mere act of typing its name and type into your source file.</p> <p>Second, you already know all there is to know about a variable by looking at it in your source code. The variable <em>ceases to exist</em> once your program is compiled. After that, it's all just bits.</p> <p>A pointer only has a type at compile time. At run time, everything that can be done to that address has already been determined. The compiler checks for that, as you already noted. Checking the type of a variable at run time is only useful in languages where a variable's type could change, as in dynamic languages. The closest Delphi comes to that is with its <code>Variant</code> type. The type of the variable is always <code>Variant</code>, but you can store many types of values in it. To find out what it holds, you can use the <code>VarType</code> function.</p> <p>Any time you could want to use <code>TypeInfo</code> to get the type information of the type associated with a variable, you can also directly name the type you're interested in; if the variable is in scope, then you can go find its declaration and use the declared type in your call to <code>TypeInfo</code>.</p> <p>If you want to pass an arbitrary address to a function and have that function discover the type information for itself, you're out of luck. You will instead need to pass the <code>PTypeInfo</code> value as an additional parameter. That's what all the built-in Delphi functions do. For example, when you call <code>New</code> on a pointer variable, the compiler inserts an additional parameter that holds the <code>PTypeInfo</code> value for the type you're allocating. When you call <code>SetLength</code> on a dynamic array, the compiler inserts a <code>PTypeInfo</code> value for the array type.</p> <p><a href="https://stackoverflow.com/questions/554100/how-to-know-what-type-is-a-var/595100#595100">The answer that you gave</a> suggests that you're looking for something other than what you asked for. Given your question, I thought you were looking for a hypothetical function that could satisfy this code:</p> <pre><code>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; </code></pre> <p>Let's use the <a href="http://jcl.svn.sourceforge.net/viewvc/jcl/trunk/jcl/source/common/JclSysUtils.pas?view=markup" rel="nofollow noreferrer"><code>IsClass</code> and <code>IsObject</code> functions from the JCL</a> to build that function:</p> <pre><code>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; </code></pre> <p>It obviously won't work for <code>S</code> or <code>Instance</code> above, but let's see what happens with <code>Obj</code>:</p> <pre><code>Info := GetVariableTypeInfo(@Obj); </code></pre> <p>That should give an access violation. <code>Obj</code> has no value, so <code>IsClass</code> and <code>IsObject</code> both will be reading an unspecified memory address, probably not one that belongs to your process. You asked for a routine that would use a variable's address as its input, but the mere address isn't enough.</p> <p>Now let's take a closer look at how <code>IsClass</code> and <code>IsObject</code> really behave. Those functions take an arbitrary value and check whether the value <em>looks like</em> it might be a value of the given kind, either object (instance) or class. Use it like this:</p> <pre><code>// 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; </code></pre> <p>Notice that the functions tell you <em>nothing</em> about the variables, only about the <em>values</em> they hold. I wouldn't really consider those functions, then, to answer the question of how to get type information about a variable.</p> <p>Furthermore, you said that all you know about the variable is its address. The functions you found do not take the address of a variable. They take the <em>value</em> of a variable. Here's a demonstration:</p> <pre><code>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; </code></pre> <p>You might object to how I'm abusing these functions by passing what's obviously garbage into them. But I think that's the <em>only</em> way it makes sense to talk about this topic. If you know you'll never have garbage values, then you don't need the function you're asking for anyway because you already know enough about your program to use real types for your variables.</p> <p>Overall, you're asking the wrong question. Instead of asking how you determine the type of a variable or the type of a value in memory, <strong>you should be asking how you got yourself into the position where you don't already know the types of your variables and your data</strong>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload