In fact that is the purpose of the Tag property, that's why it's a PtrInt after all.
Didn't used to be: Delphi defined it as a straight integer of indeterminate size. And not even as an unsigned, which would have been reasonable if they anticipated people putting pointers in that field.
In FPC it originally wasn't either, but that was already changed around a
decade ago to prepare for Delphi 64-bit compatibility which changed it from
LongInt to
NativeInt (also for a pointer it's irrelevant whether it's stored as a signed or unsigned ordinal as long as the bit width is correct, cause it needs to be cast anyway).
Also please note that
Delphi's documentation explicitly mentions that
Tag is often used for pointer values (emphasis mine):
Tag has no predefined meaning. The Tag property can store any additional integer value for the convenience of developers. Often, Tag stores a pointer. A Tag value can be typecast to the appropriate pointer type. Notice that on 64-bit platforms, all pointer types are 8 bytes in size, while on 32-bit platforms, pointer types are 4 bytes. These pointer sizes correspond to sizes of NativeInt integral values on 64-bit and 32-bit platforms.
Which I suppose raises the interesting question of what the lowest-overhead object is which can store a single string.
Depends: if you know it's less than 4 characters it would be a
UInt32 or
Int32 (e.g. for ACPI device names) (in MacPas mode FPC supports assigning 4 character strings to 32-bit ordinals
), otherwise it would probably be
PChar, followed by
ShortString (with the obvious restriction in length), then a dynamic
array of Char and then
AnsiString.