Re: [fpc-pascal] Difference between string and Tbytes as procedure arguments?

2023-11-05 Thread Michael Van Canneyt via fpc-pascal




On Sun, 5 Nov 2023, Bo Berglund via fpc-pascal wrote:



You must copy the data. The copy() function can be used for this.


Follow-up question:

Can I change the function declaration like this and preserve the content?

function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; const
Buf:  TBytes): boolean;


This does not preserve the content. The "const" means you cannot change the
pointer, so

Buf:=a;

will fail

But

Buf[0]:=1;

will still compile.



Or must I copy the argument Buf inside the function to a local BufL version?
That is what you adviced, right?


Yes.

Mcihael.
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Difference between string and Tbytes as procedure arguments?

2023-11-05 Thread Bo Berglund via fpc-pascal
On Sun, 5 Nov 2023 10:36:47 +0100 (CET), Michael Van Canneyt via fpc-pascal
 wrote:

>> So my question is this:
>> Is there a difference in handling the arguments between string, AnsiString,
>> RawByteString and TBytes in a declaration like this:
>>
>> function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; Buf:
>> AnsiString): boolean;
>>
>> and this:
>>
>> function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; Buf:
>> TBytes): boolean;
>>
>> In the first instance it looks like the function receives a *copy* of the 
>> data
>
>No, but an ansistring is copy-on-write. As soon as you change it, a copy is
>made if your routine is not the only one using the string.
>
>> in the Buf argument and in the second case it receives a pointer to the 
>> actual
>> live data such that in the first case the argument source remains untouched
>> whereas in the second case the argument source is changed just as it had been
>> declared as var...
>
>That is correct. TBytes is a fancy wrapper around a pointer with some
>reference counting added to the mix.
>
>>
>> Is there a way to simply tell Delphi/FreePascal to treat also TBytes as copy
>> rather than a pointer to the real data?
>
>You must copy the data. The copy() function can be used for this.

Follow-up question:

Can I change the function declaration like this and preserve the content?

function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; const
Buf:  TBytes): boolean;

Or must I copy the argument Buf inside the function to a local BufL version?
That is what you adviced, right?

Note: I have now found another function that changes the content of the Buf
argument and it too causes havoc...


-- 
Bo Berglund
Developer in Sweden

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


[fpc-pascal] Difference between string and Tbytes as procedure arguments?

2023-11-05 Thread Bo Berglund via fpc-pascal
I am maintaining an old utility program that started out about 20+ years ago
using Delphi7.

The utility communicates via RS232 with a measuring system in order to retrieve
and process recorded data and at the time this was started I used strings as
buffers for the serial comm.

A string at the time was really just an array of 1-byte characters but it had
useful functions for manipulating data inside so it made sense to use strings at
the time.

But as time evolved and Borland changed the meaning of string to now be
unicodestring it could no longer be used as a comm buffer, so I switched
declaration to AnsiString or even RawByteString to keep the existing utility
tools operational.

New programs I wrote would use TBytes as buffer instead...

Then about 6-7 years ago I had to do a major overhaul of the program in order to
improve the user interface and add support for switching languages in the UI and
at that time I also tried my best to replace the AnsiString buffers with TBytes
buffers. At this time I was on Delphi XE5.

It all looked OK until I recently got a call from a distributor who had
discovered that for a certain type of seldom used data collection mode the
output was corrupted when transfered to disk

And now I have found that the corruption happens inside a function that analyzes
one of the data packets where it will remove the start header record from the
buffer and then continue parsing the data items. (The buffer is sent in as a
regular argument without the var specifier).

Following this analysis in main code the buffer itself (that was used in the
previous call) is saved to disk in binary format.
And here is the problem:

The saved image of the buffer lacks the header part (30 bytes)...

So my question is this:
Is there a difference in handling the arguments between string, AnsiString,
RawByteString and TBytes in a declaration like this:

function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; Buf:
AnsiString): boolean;

and this:

function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; Buf:
TBytes): boolean;

In the first instance it looks like the function receives a *copy* of the data
in the Buf argument and in the second case it receives a pointer to the actual
live data such that in the first case the argument source remains untouched
whereas in the second case the argument source is changed just as it had been
declared as var...

Is there a way to simply tell Delphi/FreePascal to treat also TBytes as copy
rather than a pointer to the real data?


-- 
Bo Berglund
Developer in Sweden

___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] Difference between string and Tbytes as procedure arguments?

2023-11-05 Thread Michael Van Canneyt via fpc-pascal




On Sun, 5 Nov 2023, Bo Berglund via fpc-pascal wrote:


I am maintaining an old utility program that started out about 20+ years ago
using Delphi7.

The utility communicates via RS232 with a measuring system in order to retrieve
and process recorded data and at the time this was started I used strings as
buffers for the serial comm.

A string at the time was really just an array of 1-byte characters but it had
useful functions for manipulating data inside so it made sense to use strings at
the time.

But as time evolved and Borland changed the meaning of string to now be
unicodestring it could no longer be used as a comm buffer, so I switched
declaration to AnsiString or even RawByteString to keep the existing utility
tools operational.

New programs I wrote would use TBytes as buffer instead...

Then about 6-7 years ago I had to do a major overhaul of the program in order to
improve the user interface and add support for switching languages in the UI and
at that time I also tried my best to replace the AnsiString buffers with TBytes
buffers. At this time I was on Delphi XE5.

It all looked OK until I recently got a call from a distributor who had
discovered that for a certain type of seldom used data collection mode the
output was corrupted when transfered to disk

And now I have found that the corruption happens inside a function that analyzes
one of the data packets where it will remove the start header record from the
buffer and then continue parsing the data items. (The buffer is sent in as a
regular argument without the var specifier).

Following this analysis in main code the buffer itself (that was used in the
previous call) is saved to disk in binary format.
And here is the problem:

The saved image of the buffer lacks the header part (30 bytes)...

So my question is this:
Is there a difference in handling the arguments between string, AnsiString,
RawByteString and TBytes in a declaration like this:

function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; Buf:
AnsiString): boolean;

and this:

function TSSConnection.ParseCmdFileData(var SSCmdFile: TSSCommandFile; Buf:
TBytes): boolean;

In the first instance it looks like the function receives a *copy* of the data


No, but an ansistring is copy-on-write. As soon as you change it, a copy is
made if your routine is not the only one using the string.


in the Buf argument and in the second case it receives a pointer to the actual
live data such that in the first case the argument source remains untouched
whereas in the second case the argument source is changed just as it had been
declared as var...


That is correct. TBytes is a fancy wrapper around a pointer with some
reference counting added to the mix.



Is there a way to simply tell Delphi/FreePascal to treat also TBytes as copy
rather than a pointer to the real data?


You must copy the data. The copy() function can be used for this.

Michael.
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal