Search code examples
delphirecordpascal

Pascal records mixing word and bytes in records doesn't work as expected


My data is like this (one byte each two '-'):

+----+--+----+----+
|0840|0C|00AD|0840|
+----+--+----+----+

If I use this code: WRONG

Type TAlarmasRATP = record
   Funcion   : word;
   Instancia : byte;
   Err_0     : word;
   Err_1     : word;
end;

Funcion = 4008, Instancia = 0C, Err_0 = 08AD, Err_1 = 0040

If I use this code: RIGHT

Type TAlarmasRATP = record
   Funcion   : word;
   Instancia : byte;
   Err_0     : array [0..1] of byte;
   Err_1     : array [0..1] of byte;
end;

Funcion = 4008, Instancia = 0C, Err_0 = AD00, Err_1 = 4008

Why the first one is not working?


Solution

  • When a record type is used, fields are aligned according to the specification Internal data formats - Record types:

    type alignment in bytes (32bit platform)
    ordinal size of the type (i.e. 1 for Byte, 2 for Word, 4 for Cardinal, or 8 for Int64)
    real 2 for Real48, 4 for Single, 8 for Double and Extended
    ShortString 1
    Array Same as the element type of the array
    Record The largest alignment of the fields in the record
    Set Size of the type (1, 2, or 4), otherwise always 1
    all other Determined by the {$A} directive

    That means: in the first record declaration the Err_0 field will be aligned on a Word boundary and that will append one padding byte after the Instancia field.

    In the second record declaration the Err_0 field will be aligned on a Byte boundary, because it is an array of Byte and there will be no padding after the Instancia field. Since the record is not packed, a padding byte will be inserted at the end of the structure - so the record sizes will be rounded to 8 in both cases.

    If you use the packed keyword all fields in the record will be packed to the byte boundary and the size of the record will be exactly the sum of the field sizes, with no padding at the end.

    For having a record size of 7 you can simply declare:

    type TAlarmasRATP = packed record
       Funcion   : Word;
       Instancia : Byte;
       Err_0     : Word;
       Err_1     : Word;
    end;
    

    However, if you need a size of 8 you should manually add a padding byte at the end by defining just another field that you never use:

    type TAlarmasRATP = packed record
       Funcion   : Word;
       Instancia : Byte;
       Err_0     : Word;
       Err_1     : Word;
       Padding   : Byte;  // Unused
    end;