Recent

Author Topic: Is this legitimate?  (Read 4147 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1694
Is this legitimate?
« on: November 12, 2023, 09:57:13 am »
Actually I'm using following codes without any problem. Just want to confirm this is right.


var
    s : string;
    APChar : PChar;

begin
    // .....
    s := 'any string here';
    APChar := PChar(s);
    s := APChar;
    // ..
end;

Jorg3000

  • Jr. Member
  • **
  • Posts: 80
Re: Is this legitimate?
« Reply #1 on: November 12, 2023, 10:44:33 am »
Hi!
It works, but something different is happening here than you probably think.
In the last line, a string copy is created of the content starting at address APChar, and then the string copy is assigned to the variable s.

If s was initially a constant (as here), APChar still points to the constant in the program memory.

If s was not initially a constant, the old memory is released when s is reassigned to the string copy. Then APChar points to an invalid address, because the memory of initial s is no longer reserved.

« Last Edit: November 12, 2023, 10:49:14 am by Jorg3000 »

Jorg3000

  • Jr. Member
  • **
  • Posts: 80
Re: Is this legitimate?
« Reply #2 on: November 12, 2023, 10:57:43 am »
PS:
In Pascal you should work with PChar as seldom as possible, because you always need a suitable String that takes care of the memory reservation.
As soon as something changes in the string, an earlier PChar of it is most likely no longer valid.

In addition, the assignment s := APChar is internally very time-consuming and much slower than a String:=String assignment (with reference counter).
This is because with the assignment s := APChar, the memory must first be scanned to find the end of the string (#0) in order to determine the length. Then new memory must be reserved and the content copied. In contrast, with a String:=String assignment, only the reference counter needs to be incremented.

« Last Edit: November 12, 2023, 11:02:35 am by Jorg3000 »

egsuh

  • Hero Member
  • *****
  • Posts: 1694
Re: Is this legitimate?
« Reply #3 on: November 13, 2023, 03:09:17 am »
@Jorg3000,

Really appreciate your kind help. Fortunately I do not need to keep the PChar content once it has been assigned to a string type variable (nor vice versa). The example I showed is just regarding the type casting (and possibly related memory management issues).

Problem is I cannot use string type within a variant record. I might use variant, but I also have my own type of data, which led me to make a definition like following.

 
Code: Pascal  [Select][+][-]
  1.    TaqValue = record
  2.        ValueType:  TokenTypes;
  3.        case TokenTypes of
  4.           IntValue : (AsInteger: integer);
  5.           ValList : (AsList: TaqList);
  6.           Bool : (AsBoolean : Boolean);
  7.           Range: (AsRange: TRange);
  8.           FloatValue : (AsFloat: Real);
  9.           StrVal, Error : (AsPChar: PChar);  // string cannot be used.
  10.      end;

egsuh

  • Hero Member
  • *****
  • Posts: 1694
Re: Is this legitimate?
« Reply #4 on: November 13, 2023, 07:29:39 am »
I did some tests, and as said, PChar is very tricky. I'll post an example when I can point the exact problem. Currently the same codes act differently between inside the same routine and in a separate subroutine.

cdbc

  • Hero Member
  • *****
  • Posts: 2464
    • http://www.cdbc.dk
Re: Is this legitimate?
« Reply #5 on: November 13, 2023, 07:32:12 am »
Hi
One word: shortstring
Use shortstring in records, or array[0..N] of char for longer buffers.
Shortstring is a value-type, therefore the actual stringdata goes into the record, not just the pointer to them.
HTH
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6 -> FPC 3.2.2 -> Lazarus 4.0 up until Jan 2025 from then on it's both above &: KDE6/QT6 -> FPC 3.3.1 -> Lazarus 4.99

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11800
  • Debugger - SynEdit - and more
    • wiki
Re: Is this legitimate?
« Reply #6 on: November 13, 2023, 12:21:49 pm »
Doing
Code: Pascal  [Select][+][-]
  1.    MyPchar = PChar(MyAnsiString);
is fine.
So long as MyPchar is only used while
- MyAnsiString is not changed / not assigned to
- MyAnsiString does not go out of scope (e.g. local var)
- And you do not do: MyPchar[n] := '?'; // changes the string too, and all shared instances of the string

Doing the opposite is allowed to. But
Code: Pascal  [Select][+][-]
  1.   MyAnsiString := MyPChar;
does copy the entire memory of the text to which the PChar points.

And not only does it make a copy, it has to search for the terminator #0 first.
Which also means, if your string contains a #0 in the middle, then you loose data.

That can be time consuming.

As for your record, have you considered to use
Code: Pascal  [Select][+][-]
  1. type
  2.   PAnsiStrnig = ^AnsiString;
  3.   foo = record
  4. ...
  5.     case
  6. ...
  7.        StringData: PAnsiString
  8.  

Of course, since it points to the original string, the same rules apply
- the original string must be kept valid
- a copy must be made before either is changed

A copy can be made before passing the string
Code: Pascal  [Select][+][-]
  1. var ps: PAnsiString;
  2. begin
  3.   new(ps);
  4.   ps^ := WhateverString;

And before you dispose the pointer
Code: Pascal  [Select][+][-]
  1. ps^ := ''; // make sure ps^ no longer has a ref (counted ref) to the string
  2. dispose(ps);


Of course the difference to having a string in your record is, that PAnsiString is not automatically released.

So if your record goes out of scope, then the string is not released. You need to assign '' to the dereferenced pointer. (If you have several copies of the pointer, then the last one that goes out of scope)

egsuh

  • Hero Member
  • *****
  • Posts: 1694
Re: Is this legitimate?
« Reply #7 on: November 13, 2023, 03:49:06 pm »
Quote
- MyAnsiString does not go out of scope (e.g. local var)

This is exactly what MyAnsiString does --- going out of the scope.

Quote
One word: shortstring

This looks an excellent alternative. I'll try this.

I have to think over the overall solution and your advices are of great help.

Jorg3000

  • Jr. Member
  • **
  • Posts: 80
Re: Is this legitimate?
« Reply #8 on: November 14, 2023, 11:20:56 am »
A ShortString (up to 256 bytes) would always require a lot of memory, even in all other cases where no string is required.

I would implement it as follows, because then there is no need to think about the memory.
Code: Pascal  [Select][+][-]
  1. TaqValue = record
  2.        ValueType:  TokenTypes;
  3.        Str: String;
  4.        case TokenTypes of
  5.           IntValue : (AsInteger: integer);
  6.           ValList : (AsList: TaqList);
  7.           Bool : (AsBoolean : Boolean);
  8.           Range: (AsRange: TRange);
  9.           FloatValue : (AsFloat: Real);
  10.           StrVal, Error : (hasString: Boolean);
  11.        end;
  12. end;

 

TinyPortal © 2005-2018