3

I'am working on delphiXE2 and i was working on PInteger. if i did this in my delphi code

var
  P: PInteger;
  testInt: Integer;
  Scores: array[0..4] of Integer=(33,44,56,78,78);
begin
  P := @Scores;
  testInt := (P+1)^;
  WriteLn(testInt);
  ReadLn;
end;

I got this error.

[DCC Error] Project1.dpr(23): E2015 Operator not applicable to this operand type

PS: testInt := (P+1)^; is the 23rd line

However when I try this

var
  PCh: PChar;
  testchar: char;
  str: array[0..4] of char=('a','b','c','d','e');
begin
  PCh := @str;
  testchar := (PCh+1)^;
  WriteLn(testchar);
  ReadLn;
end;

it works well! The console can print 'b'!

I'm not clear about how could this happen and when ((Pointer)(P)+1)^ can work?

whosrdaddy
  • 11,720
  • 4
  • 50
  • 99
changyu
  • 81
  • 5
  • 3
    See [`Delphi pointer arithmetic`](http://stackoverflow.com/a/4305357/576719). Just add the pointer arithmetic compiler directive (works on D2009+). – LU RD Oct 22 '13 at 06:23
  • I don't see any reasons to use such awfull syntax in Delphi. Use "p: PIntegerList" instead and standard syntax "p[i]" to access items. – Andrei Galatyn Oct 22 '13 at 06:41

3 Answers3

8

Pointer arithmetic requires the compiler to know the size of the element that is pointed to. That knowledge is never known for an untyped pointer of type Pointer. So you can never do pointer arithmetic with Pointer.

Delphi has always supported pointer arithmetic for AnsiChar. More recently a compiler directive, POINTERMATH, was added to enable pointer arithmetic on all typed pointers: http://blogs.embarcadero.com/abauer/2008/01/24/38852

Note that the directive enables the additive orithmetic operators and the array indexing operator [].

So, if you enable pointer arithmetic, you can perform arithmetic on all pointers other than untyped pointers. Otherwise it is only supported for pointers to character types or pointers to byte.

With that said, your code would be much cleaner if you wrote P[1] instead. Obviously that would require pointer arithmetic to be enabled.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0
var
  P: PInteger;
  testInt: Integer;
  Scores: array [0..4] of Integer = (33, 44, 56, 78, 78);
begin
  P := @Scores[0];
  testInt := PInteger(UINT(P) + SizeOf(Integer))^;
  WriteLn(testInt);
  ReadLn;
end;

You need to use @Scores[0] to get the first element in array. And to get the next integer in array you need to add SizeOf(Integer) instead of 1 .

kot-da-vinci
  • 1,152
  • 16
  • 30
  • UINT in Delphi is LongWord (always 32bits). It means this code will be invalid in x64 mode. Question itself is strange, because it seems to be useless. Pointer to array provides much simplier syntax to access pointed array of items (where you will no be able to do such mistakes of translation pointer-integer-pointer). – Andrei Galatyn Oct 22 '13 at 06:58
  • @changyu May be Char 'a' is only 1 byte? – kot-da-vinci Oct 22 '13 at 13:48
  • @user2819514 I'm working on 64bit system.Sizeof(char) is 2 bytes. – changyu Oct 23 '13 at 00:46
0

((Pointer)(P)+1)^ can work if you use P[1] instead.

You can rewrite your code

var
  P: PIntegerList;
  testInt: Integer;
  Scores: array[0..4] of Integer=(33,44,56,78,78);
begin
  P := @Scores;
  testInt := P^[1];
  WriteLn(testInt);
  ReadLn;
end;

You don't need pointer arythmetic here (let compiler do his job for you).

Andrei Galatyn
  • 3,322
  • 2
  • 24
  • 38
  • @David: Yes, you right, but it is enabled by default (for XE3 at least) and i always use "p[i] and p.field" syntax instead of "p^[i] and p^.field" for pointers to arrays/structures, it makes code more readable. – Andrei Galatyn Oct 22 '13 at 07:32
  • @David I am sure that it is allowed by default to use p[i]/p.f syntax instead of p^[i]/p^.f, but i am not sure that it is controlled by pointermath directive (actually i think it is independent from this directive). – Andrei Galatyn Oct 22 '13 at 07:55
  • Actually I mis read your answer because I assumed that you were talking about pointer arithmetic. So, you are quite right that this answer has nothing to do with pointer arithmetic. I'm going to delete my comments above, but I do feel that your answer is wide of the mark and does not address the actual question that was asked. – David Heffernan Oct 22 '13 at 08:20
  • @David You right again :) I am trying to keep guy out of the way to dark side. Anyway, i marked your answer as usefull. – Andrei Galatyn Oct 22 '13 at 08:27
  • Actually, I think that `PIntegerList` is the dark side. There's certainly a matter of personal taste, and clearly yours and mine differ. But a pointer to an array whose high is as large as possible seems to me just a crappy workaround for the lack of pointer arithmetic. If one wants to do non-range checked array access, use pointer arithmetic. – David Heffernan Oct 22 '13 at 08:42
  • @David Yes, definition of such arrays looks bad, but it is something to do once. Unlike definition of the type, his usage is something we see in the code again and again, so this part should be as clear as possible. I use pointer arithmetic myself but only if it is really neccessary. Syntax of regular array seems to me obviously better readable than doing address calculations. – Andrei Galatyn Oct 22 '13 at 09:08
  • Try using those arrays in generic context. Also POINTERMATH also enables array indexing P[]. – David Heffernan Oct 22 '13 at 09:39
  • I've not checked this, but I'm thinking you could at least get around the range-check issue by declaring an explicit `TFiveInts = array[0..4] of integer;` and a corresponding `PFiveInts = ^TFiveInts`, then declaring `Scores : TFiveInts = ...` and `P : PFiveInts;`. Agreed that this seems like a wildly unnecessary construct in all but the most rare of circumstances, however. – J... Oct 22 '13 at 10:32