Search code examples
delphicompiler-errorsdelphi-xe4

Constant `array of cardinal` produces error 'Constant expression violates subrange bounds"


Why the following code:

const
  ANSICOLORS: array of cardinal = [
    $000000,//0
    $800000,//1, compilation error starts with this value
    $008000,//2
    $808000,//3
    $000080,//4
    $800080,//5
    $008080,//6
    $D0D0D0,//7
    $3F3F3F,//8
    $FF0000,//9
    $00FF00,//A
    $FFFF00,//B
    $0000FF,//C
    $FF00FF,//D
    $00FFFF,//E
    $FFFFFF];//F

Would produce the following compilation error under Delphi XE4 (both win32 and win64):

[dcc32 Error] Debug.pas(66): E1012 Constant expression violates subrange bounds

Isn't value $800000 within the range of Cardinal?


Solution

  • From a memory perspective, $800000 indeed is within the range of Cardinal.

    I thought it the Cardinal($800000) typecast would fix it, but it doesn't.

    Delphi XE7 and up actually compile your code correctly.

    This also fails up until Delphi XE6 with the same error:

    const
      CardinalArray: array of Cardinal = [257];
    

    I think the reason is that the Delphi compiler sees [257] as a set, despite the left side indicating it is supposed to be an array.

    This fails in XE4, but compile fine in XE7 and up:

    program Cardinals;
    
    {$APPTYPE CONSOLE}
    
    uses
      System.SysUtils;
    
    const
      CardinalArray: array of Cardinal = [257]; // fails until Delphi XE4 with "E1012 Constant expression violates subrange bounds"
    
    const
      ANSICOLORS: array of Cardinal = [
        $000000,//0
        $800000,//1, compilation error starts with this value
        $008000,//2
        $808000,//3
        $000080,//4
        $800080,//5
        $008080,//6
        $D0D0D0,//7
        $3F3F3F,//8
        $FF0000,//9
        $00FF00,//A
        $FFFF00,//B
        $0000FF,//C
        $FF00FF,//D
        $00FFFF,//E
        $FFFFFF];//F
    
    var
      AnsiColor: Cardinal;
    
    begin
      try
        for AnsiColor in AnsiColors do
          Writeln(Format('$%6.6x', [AnsiColor]));
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.
    

    Output:

    $000000
    $800000
    $008000
    $808000
    $000080
    $800080
    $008080
    $D0D0D0
    $3F3F3F
    $FF0000
    $00FF00
    $FFFF00
    $0000FF
    $FF00FF
    $00FFFF
    $FFFFFF
    

    If you can live with a non-dynamic array, then the below example works in Delphi XE4 (I tested it as far back as Delphi 2007, for XE and earlier, you have to replace System.SysUtils with SysUtils)).

    Note the switches:

    • from array of Cardinal to array[0..15] of Cardinal
    • from [ and ] to ( and )
    program Cardinals;
    
    {$APPTYPE CONSOLE}
    
    //{$R *.res}
    
    uses
      System.SysUtils;
    
    const
      ANSICOLORS: array[0..15] of Cardinal = (
        $000000,//0
        $800000,//1, compilation error starts with this value
        $008000,//2
        $808000,//3
        $000080,//4
        $800080,//5
        $008080,//6
        $D0D0D0,//7
        $3F3F3F,//8
        $FF0000,//9
        $00FF00,//A
        $FFFF00,//B
        $0000FF,//C
        $FF00FF,//D
        $00FFFF,//E
        $FFFFFF);//F
    
    var
      AnsiColor: Cardinal;
    
    begin
      try
        for AnsiColor in AnsiColors do
          Writeln(Format('$%6.6x', [AnsiColor]));
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.