Recent

Author Topic: Error: Enumeration symbols can only have values in the range of -2^31 to 2^31-1  (Read 2500 times)

daniel_sap

  • Full Member
  • ***
  • Posts: 115
Hi,

I have some DirectX related code which compiles fine with FPC 3.2.2.
Now I switched to the latest FPC and Lazarus trunk 3.3.1 and it does not compile any more.

The error is
Error: Enumeration symbols can only have values in the range of -2^31 to 2^31-1

This is the code
Code: Pascal  [Select][+][-]
  1.   TD2D1_DEBUG_LEVEL = (
  2.     D2D1_DEBUG_LEVEL_NONE = 0,
  3.     D2D1_DEBUG_LEVEL_ERROR = 1,
  4.     D2D1_DEBUG_LEVEL_WARNING = 2,
  5.     D2D1_DEBUG_LEVEL_INFORMATION = 3,
  6.     D2D1_DEBUG_LEVEL_FORCE_DWORD = $FFFFFFFF
  7.   );
  8.  
  9.   TD2D1_FACTORY_TYPE = (
  10.     D2D1_FACTORY_TYPE_SINGLE_THREADED = 0,
  11.     D2D1_FACTORY_TYPE_MULTI_THREADED = 1,
  12.     D2D1_FACTORY_TYPE_FORCE_DWORD = $FFFFFFFF
  13.   );
  14.  

I tried to fix it by using
Code: Pascal  [Select][+][-]
  1. type
  2.   {$MINENUMSIZE 4}
  3.  
with no success.

Can you advice, how could I approach this

Lazarus 4.99 (rev main_4_99-3010-gee83ece34e) FPC 3.3.1 x86_64-win64-win32/win64

440bx

  • Hero Member
  • *****
  • Posts: 6027
instead of using $FFFFFFFF use high(int32)

OTH, using MINENUMSIZE 4 will accomplish the same.

Word of advice, if you need an enumeration to be of a specific size then _test_ its size, i.e, {$if sizeof(<enumeration_type_name>) <> <desired_size>} {$FATAL enum size not as expected} {$endif}

The reason is because it is somewhat common in C to have different size enums therefore it pays to ensure no "forgotten" setting is getting in the way of getting the correct size.

It also pays to do that with structures because it is also quite common in C to have different packing for different structures.  That can easily become a source of very subtle errors.

HTH.

ETA: fixed typo.
« Last Edit: December 14, 2025, 03:40:49 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

daniel_sap

  • Full Member
  • ***
  • Posts: 115
Thank you 440bx

I replaced $FFFFFFFF with LOW(Int32) and it compiles.

I see now that there are more enumerations with negative values and the issue is for all negative values
Code: Pascal  [Select][+][-]
  1.       D2D1_PROPERTY_TYPE_FORCE_DWORD = LOW(Int32)
  2.   );
  3.  
  4.   TD2D1_PROPERTY = (
  5.       D2D1_PROPERTY_CLSID = $80000000,
  6.       D2D1_PROPERTY_DISPLAYNAME = $80000001,
  7.       D2D1_PROPERTY_AUTHOR = $80000002,
  8.       D2D1_PROPERTY_CATEGORY = $80000003,
  9.       D2D1_PROPERTY_DESCRIPTION = $80000004,
  10.       D2D1_PROPERTY_INPUTS = $80000005,
  11.       D2D1_PROPERTY_CACHED = $80000006,
  12.       D2D1_PROPERTY_PRECISION = $80000007,
  13.       D2D1_PROPERTY_MIN_INPUTS = $80000008,
  14.       D2D1_PROPERTY_MAX_INPUTS = $80000009,
  15.       D2D1_PROPERTY_FORCE_DWORD = LOW(Int32));
  16.  
  17.   TD2D1_SUBPROPERTY = (
  18.       D2D1_SUBPROPERTY_DISPLAYNAME = $80000000,
  19.       D2D1_SUBPROPERTY_ISREADONLY = $80000001,
  20.       D2D1_SUBPROPERTY_MIN = $80000002,
  21.       D2D1_SUBPROPERTY_MAX = $80000003,
  22.       D2D1_SUBPROPERTY_DEFAULT = $80000004,
  23.       D2D1_SUBPROPERTY_FIELDS = $80000005,
  24.       D2D1_SUBPROPERTY_INDEX = $80000006,
  25.       D2D1_SUBPROPERTY_FORCE_DWORD = LOW(Int32));
  26.  


May be it is improvement in FPC and $80000006 is not a valid negative number (it should has minus sign infront),
but I'm wandering if it is possible to make the Enum Double Word,
So, all of these negative values can work.

« Last Edit: December 14, 2025, 09:20:32 am by daniel_sap »

dsiders

  • Hero Member
  • *****
  • Posts: 1509

440bx

  • Hero Member
  • *****
  • Posts: 6027
You're welcome.

Keep in mind that the presence of:

D2D1_FACTORY_TYPE_FORCE_DWORD = $FFFFFFFF

is just a C-ism.  The identifier D2D1_FACTORY_TYPE_FORCE_DWORD should never be used in the code, it is there only to force the compiler to make the type 32 bit wide.

In FPC, the clean way is to set {$MINENUMSIZE 4} and not bother with declaring D2D1_FACTORY_TYPE_FORCE_DWORD since MINENUMSIZE makes it unnecessary.

Using one of your enums:
Code: Pascal  [Select][+][-]
  1. {$MINENUMSIZE 4}   { set the size! }
  2.  
  3. TD2D1_SUBPROPERTY = (
  4.       D2D1_SUBPROPERTY_DISPLAYNAME = $80000000,
  5.       D2D1_SUBPROPERTY_ISREADONLY = $80000001,
  6.       D2D1_SUBPROPERTY_MIN = $80000002,
  7.       D2D1_SUBPROPERTY_MAX = $80000003,
  8.       D2D1_SUBPROPERTY_DEFAULT = $80000004,
  9.       D2D1_SUBPROPERTY_FIELDS = $80000005,
  10.       D2D1_SUBPROPERTY_INDEX = $80000006,
  11.  
  12.       { no FORCE superfluous identifier }
  13.       );
  14.  

The one thing that is important is to ensure the enum is 4 bytes.  Because of that, I recommend testing the size of the enum {$if sizeof(<enum_type>) <> 4} because it is possible to change the {$MINENUMSIZE xxx} as many times as you want which means that it could inadvertently be left set to a value that is not appropriate for some later enum.

In general, whenever possible have the compiler assert any rules that must not be broken, such as a specific size for a particular enum.

Here is an example from a C definition ported to Pascal
Code: Pascal  [Select][+][-]
  1. type
  2.   { _SUBSYSTEM_INFORMATION_TYPE                                               }
  3.  
  4.   { https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ne-ntddk-_subsystem_information_type }
  5.   { hfile://ntddk.h                                                           }
  6.  
  7.    { 4B   75 } { ProcessSubsystemInformation                                  }
  8.  
  9.    { https://ntdoc.m417z.com/processinfoclass                                 }
  10.  
  11.   PSUBSYSTEM_INFORMATION_TYPE = ^TSUBSYSTEM_INFORMATION_TYPE;
  12.   TSUBSYSTEM_INFORMATION_TYPE =
  13.   (
  14.    {   0    0 } SubsystemInformationTypeWin32,
  15.    {   1    1 } SubsystemInformationTypeWSL,
  16.  
  17.    {   2    2 } MaxSubsystemInformationType
  18.   );
  19.  
  20.   {$if sizeof(TSUBSYSTEM_INFORMATION_TYPE) <> $4}
  21.     {$FATAL sizeof TSUBSYSTEM_INFORMATION_TYPE does not equal $4}
  22.   {$endif}
  23.  

Note the {$if sizeof ...} that ensures the enumeration is a 4 byte type.  Also note that the MAX value MaxSubsystemInformationType is NOT set, let the compiler calculate that because it allows extending the enumeration without having to reset the max value manually.

I strongly recommend you do the same for any structures you port from C, that is, check their sizes in C and Pascal and ensure they match.  It is rather common to have the C headers change structure packing multiple times in the same .h file and it is very easy to miss what the current packing is, resulting in a Pascal definition that is not the same size as the C definition.

HTH.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 18707
  • To Europe: simply sell USA bonds: dollar collapses
Usually those enums are replaced by simple constants which is much better than trying to find a work-around any other way.
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

440bx

  • Hero Member
  • *****
  • Posts: 6027
Sometimes, it is possible to replace the enum with a list of constants but, not always.

Sometimes there are instances where the enum type is used.  Having a constant is _not_ equivalent to using a type.

In general, it's good not to get gratuitously creative.  Keeping things as parallel to the original definition as possible is usually a very good thing to do that avoids a lot of subtle problems.

FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

daniel_sap

  • Full Member
  • ***
  • Posts: 115
Thank you all for the insides.
440bx, I will
- remove the FORCE_DWORD at all
- add {$MINENUMSIZE 4} - I checked this one is for Delphi compatibility and for native FPC is better to use {$Z4} or {$PACKENUM 4} 
- probably will add the checks of the size also

However I have to fix now these values
Code: Pascal  [Select][+][-]
  1.   TD2D1_PROPERTY = (
  2.       D2D1_PROPERTY_CLSID = $80000000,
  3.       D2D1_PROPERTY_DISPLAYNAME = $80000001,
  4.       D2D1_PROPERTY_AUTHOR = $80000002,
  5.       D2D1_PROPERTY_CATEGORY = $80000003,
  6.       D2D1_PROPERTY_DESCRIPTION = $80000004,
  7.       D2D1_PROPERTY_INPUTS = $80000005,
  8.       D2D1_PROPERTY_CACHED = $80000006,
  9.       D2D1_PROPERTY_PRECISION = $80000007,
  10.       D2D1_PROPERTY_MIN_INPUTS = $80000008,
  11.       D2D1_PROPERTY_MAX_INPUTS = $80000009,
  12.       D2D1_PROPERTY_FORCE_DWORD = LOW(Int32)
  13.   );
  14.  

Cause $80000001 which starts with $8xxxxxxx is still too big number for the enum.
And I was wandering what will be best. Also I'm not sure at the moment which values are the correct ones.

Code: Pascal  [Select][+][-]
  1. TD2D1_PROPERTY = (
  2.       D2D1_PROPERTY_CLSID       = -2147483648,  // еквивалент на $80000000
  3.       D2D1_PROPERTY_DISPLAYNAME = -2147483647,  // $80000001
  4.       D2D1_PROPERTY_AUTHOR      = -2147483646,  // $80000002
  5.       D2D1_PROPERTY_CATEGORY   = -2147483645,  // $80000003
  6.       D2D1_PROPERTY_DESCRIPTION = -2147483644,  // $80000004
  7.       D2D1_PROPERTY_INPUTS      = -2147483643,  // $80000005
  8.       D2D1_PROPERTY_CACHED      = -2147483642,  // $80000006
  9.       D2D1_PROPERTY_PRECISION   = -2147483641,  // $80000007
  10.       D2D1_PROPERTY_MIN_INPUTS  = -2147483640,  // $80000008
  11.       D2D1_PROPERTY_MAX_INPUTS  = -2147483639,  // $80000009
  12.       D2D1_PROPERTY_FORCE_DWORD = Low(Int32)    // -2147483648
  13.   );
  14.  

or

Code: Pascal  [Select][+][-]
  1.   TD2D1_PROPERTY = (
  2.       D2D1_PROPERTY_CLSID = -$00000000,
  3.       D2D1_PROPERTY_DISPLAYNAME = -$00000001,
  4.       D2D1_PROPERTY_AUTHOR = -$00000002,
  5.       D2D1_PROPERTY_CATEGORY = -$00000003,
  6.       D2D1_PROPERTY_DESCRIPTION = -$00000004,
  7.       D2D1_PROPERTY_INPUTS = -$00000005,
  8.       D2D1_PROPERTY_CACHED = -$00000006,
  9.       D2D1_PROPERTY_PRECISION = -$00000007,
  10.       D2D1_PROPERTY_MIN_INPUTS = -$00000008,
  11.       D2D1_PROPERTY_MAX_INPUTS = -$00000009,
  12.       D2D1_PROPERTY_FORCE_DWORD = LOW(Int32)
  13.   );
  14.  

440bx

  • Hero Member
  • *****
  • Posts: 6027
In your case I'd recommend you use {$Z4} since that's available in Delphi and FPC.

As far as the $8xxxxxxx, you should _not_ change that.

A hex number is not positive or negative, it's just a bit pattern that may be interpreted as a positive number or a negative number.  The bit pattern does not have a sign, it may not even have to be interpreted as a number, it's just a bunch of bits whose interpretation depends on where it is used.

IOW, the $8xxxxxxx will be interpreted by FPC as a negative number because FPC interprets enum constants as int32.  Regardless of the interpretation, it does not change the bit pattern.

Additionally and, this is very important, it is simply _ridiculous_ to prefix a hex number with a + or - because as stated above, hex numbers are not really numbers, just bit patterns that are written in hex because it is more convenient than writing then in binary (that would necessitate a lot of 1s and 0s.) 

Succinctly, use the 8xxxxxxx as they are defined in C.  That's actually the clean and correct way of defining the type.

HTH.

Here is an "exercise"

What does the following binary sequence represent ?

Code: Text  [Select][+][-]
  1. 10 0000

a. is it the positive number 32 ?
b. is it the ASCII space ?
c. a mask to select the 6th bit in a set of flags ?
d. any of the above ?

answer is (d) because it depends on the interpretation.  prepending a + or - to a hex number is as absurd as prepending a + or - to a binary number.  Don't do that.

FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

daniel_sap

  • Full Member
  • ***
  • Posts: 115
Thank you, 440bx

I got a compilation error when using such big values as $8xxxxxxx (see the attached screenshot)
dundx12.d2d1.pas(1407,44) Error: Enumeration symbols can only have values in the range of -2^31 to 2^31-1

I want to keep the original values, but $8xxxxxxx is still too big (bigger than 2^31-1), similar to $FFFFFFFF.


440bx

  • Hero Member
  • *****
  • Posts: 6027
The reason that's not working for you is because the pattern $80000001 is being interpreted as 2,147,483,649 not as 2,147,483,647

Don't mix hex and decimal because that can cause the compiler to interpret a number a way that is not desirable.  It's also very easy to create range problems because the negative and positives ranges are _not_ the same and mixing hex with decimal can cause the compiler to use interpretations that will cause range errors.

Your enum using only hex numbers compiles just fine:
Code: Pascal  [Select][+][-]
  1.  
  2. type
  3.   TSOME_ENUM =
  4.   (
  5.    tse1 = $80000000,
  6.    tse2 = $80000001,
  7.    tse3 = $80000002,
  8.    tse4 = $80000003,
  9.    tse5 = $80000004,
  10.    tse6 = $80000005,
  11.    tse7 = $80000006,
  12.    tse8 = $80000007,
  13.    tse9 = $80000008,
  14.    tseA = $80000009,
  15.  
  16.    // tseB = low(int32)  { commented out because it's not needed }
  17.   );
  18.  
You don't even need the "low(int32)" the magnitude of the elements forces the compiler to use 4 bytes but, for good measure you should still specify {$Z4}.

Bottom line: you're making your life hard without reason.  Define the enums just as they are in C (using hex), don't bother defining the "FORCE" constant, you don't need it.  For good measure specify {$Z4} and you should be all set.

Keep it simple... it will work.   Complicate the definition and you'll be complicating your life to gain nothing but problems.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 18707
  • To Europe: simply sell USA bonds: dollar collapses
The constant solution is also the official solution. There are no cases where Enums with values that do not fit into a pascal enum can not be translated to a series of constant values (as is done liberately all over the windows units)
The limitation is only that the whole enum becomes a series of constant. Generated code is the same as if it was enum notation.
« Last Edit: December 14, 2025, 02:44:29 pm by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

440bx

  • Hero Member
  • *****
  • Posts: 6027
you can't take the sizeof a constant.  you need the size of a type and there are cases where the size of an enum is used.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

daniel_sap

  • Full Member
  • ***
  • Posts: 115
Thank you, 440bx
For answering and explaining all kinds of questions I came up

440bx

  • Hero Member
  • *****
  • Posts: 6027
Thank you, 440bx
For answering and explaining all kinds of questions I came up
You're welcome.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018