KOCHERALKOTA harikrishna wrote:
Hello, When accessing the address of a field in a Packed record, it gives an compilation error(platform is solaris 2.6). The error says "cannot take address of bitfield <field name>".
Is that true in gpc that one cannot take the address of a field in a packed record ? Is there any other way of solving it?
First of all, taking the address of a packed record field usually doesn't make sense, for several reasons:
1) The field's offset may be any number of _bits_, not necessary divisible by 8. What should be the address of R.B in this example?
var R: packed record A: Boolean; B: Char end;
2) Even if it happens to be a whole number of bytes, the physical address of the field may not be suitable to be used as a pointer. On many machines (including Sun Sparc, AFAIK) it is not possible to access data through a pointer unless it is aligned on a 4- or 8-byte boundary, otherwise it gets a SIGSEGV or SIGBUS. This is a hardware feature, not a decision of the compiler.
3) If the size of the field is smaller than it would be in a non-packed context, you also can't use the address as a pointer. Example:
type Range = 1 .. 16000000; Rec = packed record A: Range; B: Char end;
var X: Range; Y: ^Range; Z: Rec;
Here, the size of Z.A is 3 bytes, but the size of X will be 4 (or 8) bytes, and likewise the compiler expects that Y points to data which have the full size of an integer. You can't put the address of Z.A in Y, since then the value of Y^ would include the garbage from Z.B, and an assignment to Y^ would destroy the value of Z.B.
Generally, packed records and arrays are intended to reduce the size of large data in memory, at the price that direct access to its fields is more difficult or impossible. If you need to access record fields extensively, don't pack it.
Now, if you are still sure that you can't live without taking addresses of packed record fields, here is a simple kludge. Given a declaration like this,
type PInteger = ^Integer; Rec = packed record A, B: array [0 .. 1] of Char; C: Integer end;
var R: Rec; P: PInteger;
you may put the address of R.C in P by
P := PInteger (Pointer (@R) + 4);
(Note that pointer arithmetics requires extended syntax, {$X+}.) It's also possible to write
P := PInteger (Pointer (@R) + ((BitSizeOf (R.A) + BitSizeOf (R.B)) div 8));
but you have to compute the funny number (4) anyway, to make sure that neither of the problems described above happens.
It may be wise to use macros for these expressions instead of putting them directly in the code, in case you change the record layout in the future:
{$define PtrC(X) (PInteger (Pointer (@X) + ((BitSizeOf (X.A) + BitSizeOf (X.B)) div 8)))}
P := PtrC (R);
Emil Jerabek