# How to get size of adjacent record’s fields correctly?

Suppose we have two record types TRecA and TRecB declared as shown below; in a sense the TRecB type is ‘inherited’ from TRecA.

The goal is to write a general method which clears all TRecB fields which are not ‘inherited’ from TRecA. The code below propose 3 candidate solutions TRecB.ClearX:

```    type
PRecA = ^TRecA;
TRecA = record
FieldA1: LongWord;
FieldA2: Byte;
end;

PRecB = ^TRecB;
TRecB = record
FieldA1: LongWord;
FieldA2: Byte;

FieldB1: Word;
FieldB2: LongInt;
FieldB3: Byte;
Sentinel: record end;

procedure Clear1;
procedure Clear2;
procedure Clear3;
end;

{ TRecB }

procedure TRecB.Clear1;
begin
FillChar(FieldB1, SizeOf(TRecB) - SizeOf(TRecA), 0);
end;

procedure TRecB.Clear2;
begin
FillChar(FieldB1,
SizeOf(TRecB) - Integer(@PRecB(nil)^.FieldB1), 0);
end;

procedure TRecB.Clear3;
begin
FillChar(FieldB1,
Integer(@PRecB(nil)^.Sentinel) - Integer(@PRecB(nil)^.FieldB1), 0);
end;
```

At a first glance all three ClearX methods do the same but they are not. The Clear1 solution is simply wrong while Clear2 and Clear3 are different.

To understand why it is so one need to understand how types’ sizes and alignments are calculated.

Since the 80-bit Extended was kicked out from Delphi, every type’s size is multiple of the type’s alignment. TRecA type has alignment 4 (which is the LongWord type alignment, the biggest alignment among TRecA fields), and the size of the 2nd field is less than 4, so SizeOf(TRecA) = 8.

The alignment of Word type is 2, thus the offset of FieldB1 in TRecB type is 6. That is why Clear1 solution is wrong: it may work correctly for some sets of FieldBX fields, but generally it is incorrect.

Applying the alignment rules to TRecB type we obtain the next layout:

```      TRecBLayout = record
FieldA1: LongWord;
FieldA2: Byte;
Filler1: Byte;
FieldB1: Word;
FieldB2: LongInt;
FieldB3: Byte;
Filler2: Byte;
Filler3: Byte;
Filler4: Byte;
end;
```

Filler bytes at the end are required to make TRecB size multiple of TRecB alignment (=4)

So SizeOf(TRecB) = 16, but OffsetOf(TRecB.Sentinel) = 13 (unfortunately Delphi compiler does not support OffsetOf() built-in). That is why Clear2 and Clear3 methods are different: only Clear3 does exactly what is asked – clears ‘non-inherited’ fields; Clear2 also clears filler bytes at the record’s end.