[fpc-pascal] Difference between string and Tbytes as procedure arguments?
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] Compiler probem?
Paul Renaud via fpc-pascal wrote: Hi, I have a question about some code. The following code segment generated a compiler error when I compiled it with... "A compiler error" assumes that we all have a crystal ball to look in Regards, Adriaan van Os ___ 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?
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
Re: [fpc-pascal] Difference between string and Tbytes as procedure arguments?
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
Re: [fpc-pascal] Compiler probem?
Paul Renaud via fpc-pascal schrieb am Sa., 4. Nov. 2023, 16:18: > Hi, I have a question about some code. > > The following code segment generated a compiler error when I compiled it > with... > > fpc Sample -Se -gl -al > > but not when it's compiled with... > > fpc Sample -Se -gl > > ... > Asm > LdRH R0, [ R1, R2, LSL #1 ] > End [ 'R0', 'R1' ]; > ... > > Any idea why? Its driving me crazy. > Please provide information what target your compiling for, what target you are compiling from, the compiler version you are using, the exact error you get and a complete code example. Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Creating capturers
Hairy Pixels schrieb am Sa., 4. Nov. 2023, 15:48: > > > > On Nov 4, 2023, at 4:22 PM, Sven Barth > wrote: > > > > Then don't assign them every "frame". If you just keep them around then > they aren't more expensive than a virtual method call. > > And any other mechanism would involve the heap as well, because that's > how anonymous functions that capture variables work and thus anything that > wants to store them must play by the same rules. There won't be any changes > there. > > > > The need for a universal function pointer type really isn't about the > function references even though they work for that, albeit with unneeded > overhead. > > Lets say you have a sort function which takes a compare callback > parameter. You can make the callback type "is nested" which works on global > and nested/anonymous functions but not methods. What if the user wants to > provide the compare function as a method because they're calling it in a > class which shares the code elsewhere? As the writer of the function you'd > need to make 2 versions of the function, one "is nested" and "of object". > > The writer of the sort function shouldn't need to know what kind of > function it will be passed, just that a comparison callback is provided, > right? > Then you simply make the callback function type a function reference and be done. The user can pass in any kind of function they want and *nearly* every type of function-like pointer. And if you're really worried about performance when providing such a class then simply provide overloads woth different function-like pointer types, the compiler will pick the most suitable one then. It's really not that hard as an implementer of a class. Regards, Sven > ___ 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?
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