Delphi: double indexing a pointer-of-array leads to “Array type required” error

A pointer of arrays is indexed once to get the array, then indexed again to get the element. This C-style trick should work with {$POINTERMATH ON}, but it definitely doesn't:

{$POINTERMATH ON}
...
type
  TYMMQWords = Array[0 .. 3] of UInt64;
  PYMMQWords = ^TYMMQWords; 

var 
  currentFlag: Integer; 
  temp: UInt64; 
  arrayFlags: PYMMQWords;

begin
  temp := arrayFlags[currentFlag][0];
end;

Let's take it step by step:

However, Delphi gives a compiler error here:

Array type required

Where am I wrong?

Upvotes: 1

Views: 127

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 597896

This looks like a compiler bug. The compiler is simply not interpreting this code correctly when POINTERMATH is used with a pointer to an array.

Here is another example that shows the problem is even worse:

{$POINTERMATH ON}
...
type
  TYMMQWords = Array[0 .. 3] of UInt64;
  PYMMQWords = ^TYMMQWords; 

var 
  arr: array[0..3] of TYMMQWords; 
  currentFlag: Integer; 
  temp: TYMMQWords; 
  arrayFlags: PYMMQWords;

begin
  arrayFlags := @arr[0];
  currentFlag := 3;
  temp := arrayFlags[currentFlag];   // ERROR
  temp := (arrayFlags+currentFlag)^; // OK
end;

The compiler error is completely wrong:

E2010 Incompatible types: 'TYMMQWords' and 'UInt64'

Neither temp nor arrayFlags[currentFlag] are a UInt64. arrayFlags is a pointer to a TYMMQWords, and so logically arrayFlags[currentFlag] should yield (a reference to) a TYMMQWords instance. But the compiler seems to think that indexing this pointer yields an element of the array rather than the array itself.

So, the Array type required error makes more sense when taken in this context. In arrayFlags[currentFlag][0], the compiler is clearly trying to apply the [0] to a UInt64, not to a TYMMQWords, hence the Array type required error.

I have opened a bug ticket with Embarcadero:

RSS-2077: PointerMath is broken for array types

Upvotes: 3

AmigoJack
AmigoJack

Reputation: 6174

PYMMQWords is a Pointer, not an Array.

  • arrayFlags[currentFlag] does not access an array, hence you cannot use indices here.
  • You have to dereference (^) your pointer, e.g. arrayFlags^ to come from PYMMQWords back to TYMMQWords - then you can also use indices via arrayFlags^[currentFlag].

Edit: so OP wanted this:

var 
  arrayFlags: PYMMQWords;  // Not just one TYMMQWords but many in a series.
  currentFlag: Integer;  // Indicating which of those TYMMQWords he wants to access.
  • For accessing the 1st TYMMQWords one would need to write arrayFlags^ to then access the 4 elements of that array.
  • For accessing the 3rd TYMMQWords one would need to write (arrayFlags+ 2)^ to wander 2 times the size of TYMMQWords with the pointer to then be able to access another instance of an array with 4 elements.

In sum the overall code for access should be:

UInt64value:= (arrayFlags+ currentFlag)^[index0..3];

...with currentFlag starting with 0 and being incremented as wanted.

Upvotes: -1

Related Questions