Friday, September 25, 2009

The absolute directive

This post is the about Delphi's absolute directive, according to Delphi 7 Help file
You can create a new variable that resides at the same address as another variable. To do so, put the directive absolute after the type name in the declaration of the new variable, followed by the name of an existing (previously declared) variable. For example,
var
  Str: string[32];
  StrLen: Byte absolute Str;

specifies that the variable StrLen should start at the same address as Str. Since the first byte of a short string contains the string's length, the value of StrLen is the length of Str.
You cannot initialize a variable in an absolute declaration or combine absolute with any other directives.

If that makes you dizzy then let's say you want to get a byte from a 32 bit integer(a 32 bit integer is represented on 4 bytes) then with the help of absolute directive we can use this
function getIntByte(thisInteger: Integer; ByteIndex: Byte): Byte;
var
  int_bytes: array[0..3] of Byte absolute thisInteger;
begin
  Result := int_bytes[ByteIndex];
end;

now if we want to get the second byte from the integer we can just use
getIntByte(1), because 0 is the first byte, 1 is the second and so on.
Usage example
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(getIntByte(2009, 1)));
end;

So... the absolute directive actually gives you access to a variable/parameter's memory for example if you need to get a string as an array of bytes you can simply use
procedure StrAsArrayOfByte(thisString: String);
var
  str_bytes: array of byte absolute thisString:
begin
  (* do something with "str_bytes" *)
end;

The possibilities are enormous, you just need to know when to use it, in stead of copying a variable's chars to an array of byte or using Ord(myString[Index]) just use the absolute directive!
Do not hesitate to post comments!!

5 comments:

  1. "Absolute" in this case should be less efficient than straight-forward masking and shifting, as sharing the address in memory forces the parameter to be stored on the stack, rather than leaving it in a register.

    ReplyDelete
  2. I should clarify that my comment applies to extracting the bytes out of an integer, not the str_bytes approach - which I don't recommend, treating managed types like strings and dynamic arrays as equivalent at the bit-level can lead to surprising results (e.g. exceptions, memory corruption) quite easily, if you e.g. make copies of them, or bounds-checked indexing (string stores length as count of chars, while array stores count of elements, but sizeof(char) != sizeof(byte)).

    ReplyDelete
  3. Thank you for clarifying.
    This is just a simple example of using the "absolute" directive, I couldn't think of anything else that would help beginners understand it, if you wish to correct me on anything please do so.

    ReplyDelete
  4. For me it would work great as I want to Checksum all the vars content together...

    Thanks!

    ReplyDelete
  5. Definitely it works for my Crc:

    Type

    Dpak = Packed Record
    Hdr1:Byte;
    Hdr2:Byte;
    Time:LongWord;
    Date:LongWord;
    End;

    Var
    St:Array[0..9] of Byte;
    mPak:Dpak Absolute St;

    To make simple chksum..:

    Function ChkSum:Byte
    Var
    i,Crc:Byte
    Begin
    Crc:=0;
    For i:=0 to 8 do
    Begin
    Crc:= Crc Xor St[i];
    End;
    ChkSum:=Crc;
    End;

    ReplyDelete

Blogroll(General programming and Delphi feeds)