Denis Sletkov
Denis Sletkov

Reputation: 231

Enumeration set size in x64

I found that a SizeOf(set) i different in 32-bit and 64-bit, the example below shows 5 byte for 32-bit and 8 for 64-bit. But i found nothing information about changes in SizeOf(sets) for 64-bit. Is there any Embarcadero documentation about it or compiler directive to get a similar results on 32 and 64-bit.

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses System.SysUtils;

type
{ Enumeration of properties}
TProperty1 = (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14,
  p15, p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28,
  p29, p30, p31, p32, p33, p34, p35, p36, p37);

TProperties1 = set of TProperty1;

begin
WriteLn(SizeOf(TProperties1));
ReadLn;
end.

Upvotes: 7

Views: 1541

Answers (2)

Dsm
Dsm

Reputation: 6013

Another workaround, to make sure a 32 bit machine can read a stream from a 64 bit machine and vice-versa is to create a function

function SizeCheck( const p : integer ) : integer;
begin
  if p in [5..8 ] then Result := 8 else Result := p; // adjust for 64 bit set sizes
end;  

and then use

Stream.Write(set, SizeCheck(SizeOf(set)));

Obviously only use for sets.

Upvotes: 0

Graymatter
Graymatter

Reputation: 6587

To answer your question. I couldn't find anything on the Embarcadero site regarding the differences or a compiler directive to change the behavior. My research indicates the following:

Sets have the following sizes in bytes in 32 bit:

  • Up to 8 elements - 1 Byte
  • 9 to 16 elements - 2 Bytes
  • 17 to 32 elements - 4 Bytes

From this point onwards it adds adds bytes as needed, one at a time. So 33 to 40 elements uses 5 bytes and 41 to 48 elements uses 6 bytes.

In 64 bit mode, things are slightly different:

  • Up to 8 elements - 1 Byte
  • 9 to 16 elements - 2 Bytes
  • 17 to 32 elements - 4 Bytes
  • 33 to 64 elements - 8 Bytes

From this point onwards it adds adds bytes as needed, one at a time. So 65 to 72 elements uses 9 bytes and 73 to 80 elements uses 10 bytes.

To get around this you are going to need to either use something like WriteSet in TWriter.WriteProperty and TReader.ReadSet or you can do something like this:

procedure SaveSetToStream(aStream: TStream; const aSet: TProperties1);
var
  streamData: array[0..7] of byte;
begin
  Assert(SizeOf(aSet) <= SizeOf(streamData), 'Set is too large to save. Increase the array length.');
  FillChar(streamData, SizeOf(streamData), 0);
  Move(aSet, streamData, SizeOf(aSet));
  aStream.Write(streamData, SizeOf(streamData));
end;

function ReadFromStream(aStream: TStream): TProperties1;
var
  streamData: array[0..7] of byte;
begin
  Assert(SizeOf(Result) <= SizeOf(streamData), 'Set is too large to load. Increase the array length.');
  aStream.Read(streamData, SizeOf(streamData));
  Move(streamData, Result, SizeOf(Result));
end;

Upvotes: 6

Related Questions