views:

304

answers:

4

I want to get the size of any "record" type in following function. But seems it doesn't work:

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

For example, the size of following record is 8 bytes

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

But GetDataSize(@a) always returns 1 (a is a variable of SampleRecord type of course). What should I do?

I noticed that Delphi has a procedure procedure New(var P: Pointer) which can allocate the memory block corresponds to the size of the type that P points to. How can it gets the size?

A: 

Delphi has a built-in memory manager. I believe new has access to the heap object and uses HeapSize() (or similar routines) to get the size of a block, for some pointer.

Nick D
The memory manager is replacable, but this ability is part of the definition. Key features like ansistrings and dynamic arrays won't work without it.
Marco van de Voort
+3  A: 

You cannot find the size of data structure using variable of type Pointer, because compiler cannot, make a guess and check it, since pointer can points to whatever data type you can think of. You can read some information here.

Artem Barger
+2  A: 

There's no safe way to determine the size of a record that a pointer points to. However, if you allocated the memory that the pointer points to, you can ask the size of that memory block. But then again, since you allocated that block, you should already know the size of that block! The Delphi memory manager keeps track of every block of memory that gets allocated. With information from the memory manager it is possible to find this information, if your pointer points to the beginning of a memory block. However, if you allocated a large block of memory, loaded some data in it and your pointer points to some data inside this block, this method would be quite unreliable.

Also, if you use referenced types (dynamic arrays, strings, classes, etc.) in your record, the size it returns will still be unusable since you get the size of the reference (4 bytes) instead of the size of the data that is referenced to.

The NEW() command just uses the type information of the datatype that you pass to it to get it's size. To know how it does this exactly, you could just check the Delphi sourcecode. Open \source\Win32\rtl\sys\System.pas and search for "_New". (With the underscore in front of it. Using this sourcecode might help you to understand how Delphi handles memory allocations, although the sourcecode can be really complex.

Workshop Alex
+4  A: 

The reason New knows how much memory to allocate is that New is compiler magic. It's a language built-in, so when the compiler sees you call it, it rewrites it to something like this:

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

TypeOf here is a made-up Delphi function for expository purposes. The compiler knows the declared type of foo because it knows where all your variable declarations are. You can look at the implementation of _New in System.pas. Similar rewriting occurs for Dispose so it knows what kind of finalization to do before freeing the memory.

The ideas of variables and declarations are compile-time concepts. At run time, they cease to exist. At run time, a pointer is just an address. The type of what it points to was determined at compile time. Types are what determine something's size.

If you need to write a function that accepts pointers to multiple things with different sizes, then you'll just have to provide a second parameter that describes what the first one points to.

Check out another question here, "How to know what type is a var." The asker wondered how to determine more information about a variable given only its address.

Rob Kennedy
@Rob, thanks for the detail info, I believe it's complier magic. I think it also explains why there isn't a "New" procedure.
trudger