Search code examples
delphirecorddiscriminated-union

Absolute addressing fields in a record type


I am attempting to interface with an embedded system that transmits and receives data with a fairly simple format but has strict sizing requirements.

In C, you would use a union type to expose some variable data with potentially different types located at the same spot in memory. Add a variable of this union type to a struct, and then you can (carefully) refer to that struct field with various names and types:

for simplicity, please ignore byte alignment and packing

typedef enum { F1_V1, F1_V2, F1_V3 } FLAG_1_T;
typedef enum { F2_V1, F2_V1        } FLAG_2_T;

typedef union
{
  FLAG_1_T flag_1;
  FLAG_2_T flag_2;
}
FLAG_T;

typedef struct
{
  BYTE_T  id;
  INT32_T value;
  FLAG_T  flag;
}
DATA_ITEM_T;

So now I can interpret the flag field as either FLAG_1_T or FLAG_2_T.

I would like to use this same sort of approach in Delphi 2010. I've tried to accomplish this by using absolute addressing for fields of a record:

type
  FLAG_1_T = ( F1_V1, F1_V2, F1_V3 );
  FLAG_2_T = ( F1_V1, F1_V2        );

type
  DATA_ITEM_T = record
    id     : BYTE_T;
    value  : INT32_T;
    flag_1 : FLAG_1_T;
    flag_2 : FLAG_2_T absolute flag_1;
  end;

But this fails to compile with syntax error E2029 ';' expected but identifier 'absolute' found.

If I bring those flag declarations outside of the record type definition (but at the same scope as the record type def), it compiles fine:

note that this is useless for what I'm trying to accomplish

type
  FLAG_1_T = ( F1_V1, F1_V2, F1_V3 );
  FLAG_2_T = ( F1_V1, F1_V2        );

type
  DATA_ITEM_T = record
    id     : BYTE_T;
    value  : INT32_T;
  end;

var
  flag_1 : FLAG_1_T;
  flag_2 : FLAG_2_T absolute flag_1;

So why can't I do this within a record? Is there another way to accomplish this?


Solution

  • You can translate a C union to Delphi using a record type with a variant part:

    type
      FLAG_T = record
        case Boolean of
          False: (flag_1: FLAG_1_T);
          True: (flag_2: FLAG_2_T);
      end;