Board index » delphi » Why won't this code work?

Why won't this code work?

You wouldn't think it by this question, but I have been writing C and assembly
for 15 years, and Delphi for 4 or so. Luckily I have largely avoided pointers in
Delphi until now. My syntax below may not be exactly correct, but I made it up
on the fly.

Why won't this work?:

type MyType
??? blah
??? blah
end;

procedure??? MyProc;
var
??? Ptr?????? :Pointer;
begin
??? Ptr:=@AddressOfBuffer;
??? While (SomethingIsTrue) do
??? begin
??????? DoSomethingWith(Ptr);
??????? Ptr:=Ptr+SizeOf(MyType);??? //This is the problem
??? end;
end;

I guess my question is really; How do you add a number to a pointer? You can
Inc() the pointer, but can't add to it. I know I can make a type that is a
pointer to MyType and Inc() that, but that will not work for me in this case.

--
Thanks,
Ron Davis
c...@oaktree.net
?

 

Re:Why won't this code work?


Hello

Try this:
P := Pointer(Integer(P) + SizeOf(Something));

Regards,

Lars Arvidsson

Ron Davis skrev i meddelandet <37C6D734.4EEF5...@Oaktree.net>...

Quote
>You wouldn't think it by this question, but I have been writing C and
assembly
>for 15 years, and Delphi for 4 or so. Luckily I have largely avoided
pointers in
>Delphi until now. My syntax below may not be exactly correct, but I made it
up
>on the fly.

>Why won't this work?:

>type MyType
> blah
> blah
>end;

>procedure MyProc;
>var
> Ptr :Pointer;
>begin
> Ptr:=@AddressOfBuffer;
> While (SomethingIsTrue) do
> begin
> DoSomethingWith(Ptr);
> Ptr:=Ptr+SizeOf(MyType); //This is the problem
> end;
>end;

>I guess my question is really; How do you add a number to a pointer? You
can
>Inc() the pointer, but can't add to it. I know I can make a type that is a
>pointer to MyType and Inc() that, but that will not work for me in this
case.

>--
>Thanks,
>Ron Davis
>c...@oaktree.net

Re:Why won't this code work?


Quote
Ron Davis <c...@Oaktree.net> wrote in message

news:37C6D734.4EEF5011@Oaktree.net...

Quote
> type MyType
> blah
> blah
> end;

I'll assume "type MyType = record", since records are easy, though I think
it should work for most other types.  AnsiStrings can be complicated when
trated as pointers, since the reference counting is not as stable.

Quote
> procedure MyProc;
> var
> Ptr :Pointer;
> begin
> Ptr:=@AddressOfBuffer;
> While (SomethingIsTrue) do
> begin
> DoSomethingWith(Ptr);
> Ptr:=Ptr+SizeOf(MyType); file://This is the problem
> end;
> end;

> I guess my question is really; How do you add a number to a pointer? You
can
> Inc() the pointer, but can't add to it. I know I can make a type that is a
> pointer to MyType and Inc() that, but that will not work for me in this

case.

It looks like you're duplicating what arrays already do.  They handle all
the pointer offsets for you.  Try setting up something like this:

type
    PMyTypeArray = ^TMyTypeArray;
    TMyTypeArray = array[0..MaxInt div SizeOf(TMyType) - 1] of TMyType;

Since your buffer is already an array of TMyType, the compiler should be
able to handle the following code without much trouble.  This version does
not require that you change the range checking compiler switch, whereas some
other dynamic array implementations will use it to conserve stack space.

procedure MyProc;
var
    Ptr: PMyTypeArray;
    i: Integer;
begin
    Ptr := AddressOfBuffer; // or @Buffer.  @AddressOfBuffer is redundant,
no?
    i := 0;
    while SomethingIsTrue and (i < LengthOfBuffer div SizeOf(TMyType)) do
begin
        DoSomethingWith(Ptr^[i]);
        Inc(i);
    end;
end;

--Rob

Re:Why won't this code work?


Quote
Ron Davis wrote:

> You wouldn't think it by this question, but I have been writing C and assembly
> for 15 years, and Delphi for 4 or so. Luckily I have largely avoided pointers in
> Delphi until now. My syntax below may not be exactly correct, but I made it up
> on the fly.

> Why won't this work?:

> type MyType
>     blah
>     blah
> end;

> procedure    MyProc;
> var
>     Ptr       :Pointer;
> begin
>     Ptr:=@AddressOfBuffer;
>     While (SomethingIsTrue) do
>     begin
>         DoSomethingWith(Ptr);
>         Ptr:=Ptr+SizeOf(MyType);    //This is the problem
>     end;
> end;
> I guess my question is really; How do you add a number to a pointer?

Yep. Just to give you a bit of background, I've been using Pascal for
about 10 years and C for a couple so I'm looking at things the other way
round.

Answer #0: The pointer increment extension.

Quote
> You can
> Inc() the pointer, but can't add to it. I know I can make a type that is a
> pointer to MyType and Inc() that, but that will not work for me in this case.

Perhaps you're not aware that increment can take two arguments? If you
have:

type
  PByte=^Byte; {effectively a char *}

var
  MyPtr:PByte;

Then it's perfectly possible to do:

Inc(MyPtr,6);

Which adds 6 to it. The god news is that if/when pointers become 64 bit,
this will still work. Of course, you're probably more likely to do:

Inc(MyPtr,Sizeof(ElementType));

or if you're using structures where the first byte of the structure is a
size, then you might end up doing:

Inc(MyPtr,MyPtr^);

Answer #1: The quick hack.

If you really want to hack things and rely on the details of the 32 bit
memory model, then you can do typecasts to and from the integer type:

MyPtr:=PByte(Integer(MyPtr)+6);

Note that integer is a signed type, and this only works because the
virtual addresses of most processes, when mapped to an integer, turn out
to be positive. This isn't the case if you're writing system code!

Answer #2: Other useful hints and tips.

If you're dealing with arbitrary buffers of data, and you wish to hide
the pointerisms from the caller of a procedure, you can use a pointer to
memory, and hide it from the caller as an untyped const or var
parameter:

Here are a couple of examples of procedures (well, actually class
methods) that read from and write to an arbitrary memory buffer:

function TMCHMemoryStream.Write(const Buffer;Count:longint):longint;

var
  Src:Pointer;

begin
<snip>
  Src := @Buffer;
<snip>
end;

function TMCHMemoryStream.Read(var Buffer;Count:longint):longint;

var
  Dest:pointer;

begin
<snip>
    Dest := @Buffer;
<snip>
end;

In these two cases, instead of requiring the procedure or function to
take a pointer explicitly, you use "var" or "const" to tell the compiler
that the procedure or function requires a variable parameter of any
type. You then (in some sense) know that the compiler optimises this by
passing a pointer to the variable on the stack, and you get that
"hidden" value by taking the address of the const or var parameter.

Very nice, and it means that you can worry about the pointers, whilst
your users just have to provide a variable without worrying about
pointers. Eg they might do:

var
  myarray:array[0..20] of integer;

AmountRead=MyStream.Read(myarray,sizeof(myarray));

Which is kinda neat, and relatively safe... the user does not need to
take the address of anything.

Answer #3: Think about the problem differently.

I'll assume that you are doing something relatively low level involving
streams of bytes (perhaps parsing some input stream?) that requires
direct pointer access.

Apart from that, there is often little need to use pointers explicitly
in Delphi. It's not that Delphi doesn't use pointers.... on the
contrary, if anything it uses pointers somewhat more than C or C++ ...
it's just that those pointers are not immediately obvious... they don't
stand out with ^ or @ (ie C's * or &) in the code.

The secret is (as you may, or may not have grasped) that every class
instance is in fact a pointer, and every time you type a "." after a
class variable, you are performing a pointer indirection. So: Golden
Rule #1 of delphi programming:

If you're ever writing a data structure that involves pointers, and
doesn't implicitly require low level access (99% don't), then rewrite
the thing using classes. You will save lots of time and energy.

MH.

--
Martin Harvey.
mar...@aziraphale.demon.co.uk
mc...@harvey27.demon.co.uk
http://www.harvey27.demon.co.uk/mch24/

Other Threads