Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2011-02

Use of Move()?

7 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bo Berglund

I think I have made an error.....
I have created a generalized buffer handler for my project and here I have this function to read data from the buffer.

function TSSCommBuf.Read(Dest: Pointer; Count: Cardinal): Cardinal;
var
  num: Cardinal;
begin
  num := FWriteIndex - FReadIndex;  //Remaining data bytes in buffer
  if num >= Count then
    num := Count;
  if num > 0 then
  begin
    Move(FBuf[FReadIndex], Dest, num);
    FReadIndex := FReadIndex + num;
  end;
  Result := num;
end;
FWriteIndex is the next location in the byte array to write to and
FReadIndex is the next location to read from.
FBuf is a dynamic array of byte declared as:
type
  TByteArr = array of byte;
FBuf: TByteArr;

What happens here is that when I call the function to retrieve a byte as follows it returns incorrect data.

function TSSCommBuf.Read(var Data: byte): boolean;
begin
  Result := Read(@Data, SizeOf(Data)) = SizeOf(Data);
end;

What I suspect is that I am not using the correct syntax for the Move call.
I think I have read that there are subtle differences in FPC versus Delphi concerning such things as addresses.....

Bo Berglund

Reply by email

Burkhard Carstens
to Bo Berglund
Bo Berglund wrote 14 lines
I think I have made an error..... I have created a generalized buffer handler for my project and here I have this function to read data from the buffer. function TSSCommBuf.Read(Dest: Pointer; Count: Cardinal): Cardinal; var num: Cardinal; begin num := FWriteIndex - FReadIndex; //Remaining data bytes in buffer if num >= Count then num := Count; if num > 0 then begin Move(FBuf[FReadIndex], Dest, num);

didn't read further, but: try Dest^ ..
(quick guess)

regards
Burkhard

Reply by email

Bo Berglund
to Burkhard Carstens
Burkhard Carstens wrote 19 lines
Am Dienstag, 1. Februar 2011 21:03 schrieb Bo Berglund: > I think I have made an error..... > I have created a generalized buffer handler for my project and here I > have this function to read data from the buffer. > > function TSSCommBuf.Read(Dest: Pointer; Count: Cardinal): Cardinal; > var > num: Cardinal; > begin > num := FWriteIndex - FReadIndex; //Remaining data bytes in buffer > if num >= Count then > num := Count; > if num > 0 then > begin > Move(FBuf[FReadIndex], Dest, num); didn't read further, but: try Dest^ .. (quick guess)

Did not work, but I am using Move() in a way that has worked for me using Delphi for many years, so it may have to do with Delphi vs fpc differences....

What I usually do is the following:

Move(Source, Dest, Count);
where normally Source is an array, for example a string and Dest is for example a multi-byte variable:

Move(SrcArr[Index], DestVar, SizeOf(DestVar);

Delphi manages to deduce what to use correctly so that the source is the address of the array element Index and destination is the address of the variable.

But when using FPC this may not really happen and this is what I am trying to find out how to solve.
Here is the function that actually stuffs data into the buffer array:

function TSSCommBuf.Write(Source: Pointer; Count: Cardinal): boolean;
begin
  Result := false;
  if (FBufSize - FWriteIndex) < Count then
    ExpandBuffer(FWriteIndex - FBufSize + Count);
  Move(Source, FBuf[FWriteIndex], Count);
  FWriteIndex := FWriteIndex + Count;
  Result := true;
end;

Do I need to put @ or ^ characters in any part of this to make the Move function work correctly?

Bo Berglund

Reply by email

Marc Weustink
to Bo Berglund
Bo Berglund wrote 26 lines
On Tue, 1 Feb 2011 21:18:57 +0100, Burkhard Carstens wrote: > Am Dienstag, 1. Februar 2011 21:03 schrieb Bo Berglund: >> I think I have made an error..... >> I have created a generalized buffer handler for my project and here I >> have this function to read data from the buffer. >> >> function TSSCommBuf.Read(Dest: Pointer; Count: Cardinal): Cardinal; >> var >> num: Cardinal; >> begin >> num := FWriteIndex - FReadIndex; //Remaining data bytes in buffer >> if num>= Count then >> num := Count; >> if num> 0 then >> begin >> Move(FBuf[FReadIndex], Dest, num); > > didn't read further, but: try Dest^ .. > (quick guess) > Did not work, but I am using Move() in a way that has worked for me using Delphi for many years, so it may have to do with Delphi vs fpc differences....

Also in Delphi you must use Dest^, otherwise you are overwriting your pointer. (unless they have some overloaded Move)

Show quoted text 7 lines
What I usually do is the following: Move(Source, Dest, Count); where normally Source is an array, for example a string and Dest is for example a multi-byte variable: Move(SrcArr[Index], DestVar, SizeOf(DestVar);

Just tested:

program MoveTest;
{$mode objfpc}{$H+}
uses
   SysUtils;
var
   S: String;
   I: Integer;
   P: Pointer;
begin
   S := 'Bla';
   S := S + S;
   P := @I;
   Move(S[1], P^, SizeOf(I));
   WriteLn(Format('%x %x %x %x %8.8x', [Ord(S[1]), Ord(S[2]), Ord(S[3]),
Ord(S[4]), i]));
end.
$ ./movetest
42 6C 61 42 42616C42

Marc

Reply by email

Bo Berglund
to Marc Weustink
Marc Weustink wrote 24 lines
Just tested: program MoveTest; {$mode objfpc}{$H+} uses SysUtils; var S: String; I: Integer; P: Pointer; begin S := 'Bla'; S := S + S; P := @I; Move(S[1], P^, SizeOf(I)); WriteLn(Format('%x %x %x %x %8.8x', [Ord(S[1]), Ord(S[2]), Ord(S[3]), Ord(S[4]), i])); end. $ ./movetest 42 6C 61 42 42616C42

My code is a bit more complex because I want to be able to read and write different types of variables to the buffer handler. As an example I have the case of a string variable. To write it into the buffer I use this overloaded write:

function TSSCommBuf.Write(const Source: string): boolean;
begin
  Result := Write(@Source[1], Length(Source));
end;

and for a Cardinal argument I use this:

function TSSCommBuf.Write(const Source: Cardinal): boolean;
begin
  Result := Write(@Source, SizeOf(Source));
end;

both of which then calls the main Write:

function TSSCommBuf.Write(Source: Pointer; Count: Cardinal): boolean;
var
  b: byte; //For debugging, will be removed later
  Dst: Pointer; //Suggestion from Marc Weustink
begin
  Result := false;
  //Check buffer size and grow if needed
  if (FBufSize - FWriteIndex) < Count then
    ExpandBuffer(FWriteIndex - FBufSize + Count);
  Dst := @FBuf[FWriteIndex];
  Move(Source, Dst^, Count); // Source and Dst are pointers
  b := FBuf[FWriteIndex]; //To check what actually was written
  FWriteIndex := FWriteIndex + Count;
  Result := true;
end;

When I call the Write method with a string argument I get first to the small overloaded function, which unifies the arguments and calls the main Write.

But when I test this with the string containing the single char #6 then the value that actually gets written is #64....

So somehow I am missing something important here...

Bo Berglund

Reply by email

Marc Weustink
to Bo Berglund
Bo Berglund wrote 71 lines
On Tue, 01 Feb 2011 23:33:58 +0100, Marc Weustink wrote: > > Just tested: > > program MoveTest; > {$mode objfpc}{$H+} > uses > SysUtils; > var > S: String; > I: Integer; > P: Pointer; > begin > S := 'Bla'; > S := S + S; > P := @I; > Move(S[1], P^, SizeOf(I)); > > WriteLn(Format('%x %x %x %x %8.8x', [Ord(S[1]), Ord(S[2]), Ord(S[3]), > Ord(S[4]), i])); > end. > > $ ./movetest > 42 6C 61 42 42616C42 > My code is a bit more complex because I want to be able to read and write different types of variables to the buffer handler. As an example I have the case of a string variable. To write it into the buffer I use this overloaded write: function TSSCommBuf.Write(const Source: string): boolean; begin Result := Write(@Source[1], Length(Source)); end; and for a Cardinal argument I use this: function TSSCommBuf.Write(const Source: Cardinal): boolean; begin Result := Write(@Source, SizeOf(Source)); end; both of which then calls the main Write: function TSSCommBuf.Write(Source: Pointer; Count: Cardinal): boolean; var b: byte; //For debugging, will be removed later Dst: Pointer; //Suggestion from Marc Weustink begin Result := false; //Check buffer size and grow if needed if (FBufSize - FWriteIndex)< Count then ExpandBuffer(FWriteIndex - FBufSize + Count); Dst := @FBuf[FWriteIndex]; Move(Source, Dst^, Count); // Source and Dst are pointers b := FBuf[FWriteIndex]; //To check what actually was written FWriteIndex := FWriteIndex + Count; Result := true; end; When I call the Write method with a string argument I get first to the small overloaded function, which unifies the arguments and calls the main Write. But when I test this with the string containing the single char #6 then the value that actually gets written is #64.... So somehow I am missing something important here...

Move expects 2 untyped parameters, so dereference your pointers

   Move(Source^, Dst^, Count); // Source and Dst are pointers

Marc

Reply by email

Bo Berglund
to Marc Weustink
Marc Weustink wrote 6 lines
> So somehow I am missing something important here... Move expects 2 untyped parameters, so dereference your pointers Move(Source^, Dst^, Count); // Source and Dst are pointers

Thanks!
Finally my buffer handler works as expected for the initial one-char test. :-)

Bo Berglund

Reply by email