In short, I think, Delphi compares four byte enumeration values as Integer
(signed), not as Cardinal
(unsigned), as opposed to the documentation:
Finally, if an enumerated type is declared in the {$Z4} state, it is stored as an unsigned double word.
Is there any way to enforce the comparison to be unsigned, without casting the values to Cardinal
?
Demo:
program FourByteEnum;
{$APPTYPE CONSOLE}
const
cvr20100101 = 1001010000; //* 2010-01-01, 00:00 - timestamp used as version
cvr20200503 = 2005030000;
cvr20250303 = 2503030000;
type
{$MINENUMSIZE 4}
TEnumVersion = (
evr20100101 = 1001010000,
evr20200503 = 2005030000,
evr20250303 = 2503030000
);
var
CardinalVersion: Cardinal;
EnumVersion: TEnumVersion;
begin
CardinalVersion := cvr20200503;
writeln('CardinalVersion > cvr20250303 : ', CardinalVersion > cvr20250303); // FALSE
EnumVersion := evr20200503;
writeln('EnumVersion > evr20250303 : ', EnumVersion > evr20250303); // TRUE
writeln('Ord(evr20200503) : ', Ord(evr20200503)); // 2005030000
writeln('Ord(evr20250303) : ', Ord(evr20250303)); // -1791937296
readln;
end.
The long story is not so interesting to others, so I left it to the end:
I slowly shoot myself in my foot during the years while maintaining a project. There was a record type with a version: Integer
field at the very beginning. The record is binary serialized to disk, and for some reason, I started to use the actual date and time encoded in the version field. Some times ago the encoded value overflowed on MaxInt
, and then I changed the type to Cardinal
. It was fine.
Now I wanted to refactor the type of the version field to a four byte enum. It has an advantage of type safety, and during the process, the code became non-compilable, so I found some version value comparisons on literals not extracted as version constants. But then I realized the problem above.
So, should I revert the type of the version field to Cardinal
, or there is an option to use it as a four byte enum?