Sign in Join

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

Mailing lists / fpc-pascal / 2014-03

Library.StringFunction() : PChar => NO

15 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

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

Fred van Stappen

Hello great fpc people.

It is about functions dealing with string inside a library...

If i use that kind of function inside the library :

> InLibStringFunction() : PChar ;

It will be the memory manager of the library who deals with the PChar result. So difficult for the main application to manage the memory used by PChar.

Some good guru show me the way how to deal with string result inside a library :

> In library :
MyStrTest(inStr:Pchar; outStr:pChar; size:integer):integer; cdecl;
var
  MyRealResult :string;
begin
 MyRealResult :=   inStr + ' added by function ';
  Result := length(myRealResult);
if size >= result then move(OutStr[0], MyRealResult[1], result);
end;
> And in main program :
 function  testLib(InputText : string) : string ;
var
 MyStrOut : string;
  MyLen : integer;
begin
   MyLen := MyStrTest( @InputText[1],@MyStrOut[1], 0);
   SetLEngth(MyStrOut, mylen+1);
   FillChar(MyStrOut[1], MyLen+1,0);
   MyStrTest(@InputText[1], @MyStrOut[1], 0);
 result := MyStrOut ;
end;

I have test it but, sadly, MyStrOut is always a empty string... ;-(

Could somebody give a working code ?
Or maybe, does it exist a better way to do it ?

Many thanks.

Fred.

Reply by email

leledumbo
to Fred van Stappen
It will be the memory manager of the library who deals with the PChar

result.
So difficult for the main application to manage the memory used by PChar.

It's not a problem, as long as you provide an API to dispose the memory used by the returned PChar. The responsibility of calling this API is delegated to the application.

Show quoted text 8 lines
MyStrTest(inStr:Pchar; outStr:pChar; size:integer):integer; cdecl; var MyRealResult :string; begin MyRealResult := inStr + ' added by function '; Result := length(myRealResult); if size >= result then move(OutStr[0], MyRealResult[1], result); end;

Wrong usage of Move
(http://www.freepascal.org/docs-html/rtl/system/move.html). First parameter is source, second is destination. So you have to swap them in above function.

Show quoted text 11 lines
function testLib(InputText : string) : string ; var MyStrOut : string; MyLen : integer; begin MyLen := MyStrTest( @InputText[1],@MyStrOut[1], 0); SetLEngth(MyStrOut, mylen+1); FillChar(MyStrOut[1], MyLen+1,0); MyStrTest(@InputText[1], @MyStrOut[1], 0); result := MyStrOut ; end;

Wrong usage of the MyStrTest. Here you give Size parameter of value 0, while in MyStrTest... see that last if statement? Guess yourself. Moreover, after the first call, you set the length and then filling the space with 0. The 2nd MyStrTest call doesn't differ from the first.

From the code, I can guess what that good guru means. First call he just

wants to get the length, therefore giving size 0. He then allocates enough storage and re-call the function, but this time he seems to have a typo. The 2nd MyStrTest call should have size parameter set to MyLen.

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Library-StringFunction-PChar-NO-tp5718594p5718595.html Sent from the Free Pascal - General mailing list .

Reply by email

Fred van Stappen
to leledumbo
Show quoted text 48 lines
Date: Fri, 14 Mar 2014 08:20:46 -0700 From: To: Subject: Re: [fpc-pascal] Library.StringFunction() : PChar => NO > It will be the memory manager of the library who deals with the PChar result. So difficult for the main application to manage the memory used by PChar. It's not a problem, as long as you provide an API to dispose the memory used by the returned PChar. The responsibility of calling this API is delegated to the application. > MyStrTest(inStr:Pchar; outStr:pChar; size:integer):integer; cdecl; > var > MyRealResult :string; > begin > MyRealResult := inStr + ' added by function '; > Result := length(myRealResult); > if size >= result then move(OutStr[0], MyRealResult[1], result); > end; Wrong usage of Move (http://www.freepascal.org/docs-html/rtl/system/move.html). First parameter is source, second is destination. So you have to swap them in above function. > function testLib(InputText : string) : string ; > var > MyStrOut : string; > MyLen : integer; > begin > MyLen := MyStrTest( @InputText[1],@MyStrOut[1], 0); > SetLEngth(MyStrOut, mylen+1); > FillChar(MyStrOut[1], MyLen+1,0); > MyStrTest(@InputText[1], @MyStrOut[1], 0); > result := MyStrOut ; > end; Wrong usage of the MyStrTest. Here you give Size parameter of value 0, while in MyStrTest... see that last if statement? Guess yourself. Moreover, after the first call, you set the length and then filling the space with 0. The 2nd MyStrTest call doesn't differ from the first. From the code, I can guess what that good guru means. First call he just wants to get the length, therefore giving size 0. He then allocates enough storage and re-call the function, but this time he seems to have a typo. The 2nd MyStrTest call should have size parameter set to MyLen.

@ leledumbo, like always => brilliant => Tetras * Megas thanks. ;-)

Reply by email

Fred van Stappen
to leledumbo: result. So difficult for the main application to manage the memory used by PChar. It's…
It's not a problem, as long as you provide an API to dispose the memory used by the returned PChar. The responsibility of calling this API is delegated to the application.

Yep, with pleasure,... but how to provide an API (and what do you mean with "provide an API to dispose the memory") ?

=> In short, what must i code to do that ?

Re-Many thanks.

Fred

Reply by email

Sven Barth
to Fred van Stappen
Fred van Stappen wrote 9 lines
> It's not a problem, as long as you provide an API to dispose the memory > used by the returned PChar. > The responsibility of calling this API is delegated > to the application. Yep, with pleasure,... but how to provide an API (and what do you mean with "provide an API to dispose the memory") ? => In short, what must i code to do that ?

Inside your library you normally do this when creating a string result:

=== code begin ===

function InLibStringFunction: PChar; // of course declared as cdecl ;)
const
   MyString: AnsiString = 'Hello World'; // this string could also come
frome somewhere else in your library
begin
   Result := GetMem(Length(MyString) + 1);
   Move(@MyString[1], Result, Length(MyString));
   Result[Length(MyString)] := 0;
end;

=== code end ===

Note: if your MyString is valid through the complete lifetime it could be used you can also use "Result := PChar(MyString);" instead, but if your string is e.g. a variable inside the function or a variable inside another function you must copy its content.

If you now allocated a PChar using GetMem you add this function as well and export it from the library:

=== code begin ===

procedure InLibFreeString(aStr: PChar);
begin
   FreeMem(aStr);
end;

=== code end ===

One could of course now extend the API with additional checks. E.g. so that you know that the string was really allocated by the library and not by e.g. the program using it. But maybe the heap manager already checks this, I don't know currently.

Regards,
Sven

Reply by email

Fred van Stappen
to Sven Barth
Show quoted text 56 lines
Date: Fri, 14 Mar 2014 23:11:14 +0100 From: To: Subject: Re: [fpc-pascal] Library.StringFunction() : PChar => NO On 14.03.2014 22:07, Fred van Stappen wrote: > > It's not a problem, as long as you provide an API to dispose the memory > > used by the returned PChar. > > The responsibility of calling this API is delegated > > to the application. > > Yep, with pleasure,... but how to provide an API (and what do you mean > with "provide an API to dispose the memory") ? > > => In short, what must i code to do that ? Inside your library you normally do this when creating a string result: === code begin === function InLibStringFunction: PChar; // of course declared as cdecl ;) const MyString: AnsiString = 'Hello World'; // this string could also come frome somewhere else in your library begin Result := GetMem(Length(MyString) + 1); Move(@MyString[1], Result, Length(MyString)); Result[Length(MyString)] := 0; end; === code end === Note: if your MyString is valid through the complete lifetime it could be used you can also use "Result := PChar(MyString);" instead, but if your string is e.g. a variable inside the function or a variable inside another function you must copy its content. If you now allocated a PChar using GetMem you add this function as well and export it from the library: === code begin === procedure InLibFreeString(aStr: PChar); begin FreeMem(aStr); end; === code end === One could of course now extend the API with additional checks. E.g. so that you know that the string was really allocated by the library and not by e.g. the program using it. But maybe the heap manager already checks this, I don't know currently. Regards, Sven

Yep, Sven, excellent and hyper clear.

Hum, i think that this code must go somewhere in wiki. If you agree i will add it into fpc wiki.

Many thanks.

Fred.

Reply by email

Fred van Stappen
to Sven Barth: Inside your library you normally do this when creating a string result: === code begin ===
Note: if your MyString is valid through the complete lifetime it could be used you can also use "Result := PChar(MyString);"

Hum, to be sure that i understand...

type
  TStringClass = class(TObject)
    Name: AnsiString;  //// does not change
    SomeText: AnsiString; ///// may change..
  end;
var
AStringClass : TStringClass;

....

function GetName: PChar;  cdecl ;
begin
result := PChar(AStringClass.Name);
end;
function GetSomeText: PChar;  cdecl ;
var
   MyString: AnsiString ;
begin
 MyString := AStringClass.SomeText ;
   Result := GetMem(Length(MyString) + 1);
   Move(@MyString[1], Result, Length(MyString));
   Result[Length(MyString)] := 0;
end;

Is it OK ?

Thanks.

Reply by email

Sven Barth
to Fred van Stappen: Yep, Sven, excellent and hyper clear. Hum, i think that this code must go somewhere in…
"Fred van Stappen" wrote 9 lines
> Date: Fri, 14 Mar 2014 23:11:14 +0100 > From: > To: > Subject: Re: [fpc-pascal] Library.StringFunction() : PChar => NO > > On 14.03.2014 22:07, Fred van Stappen wrote: > > > It's not a problem, as long as you provide an API to dispose the

memory

Show quoted text 54 lines
> > > used by the returned PChar. > > > The responsibility of calling this API is delegated > > > to the application. > > > > Yep, with pleasure,... but how to provide an API (and what do you mean > > with "provide an API to dispose the memory") ? > > > > => In short, what must i code to do that ? > > Inside your library you normally do this when creating a string result: > > === code begin === > > function InLibStringFunction: PChar; // of course declared as cdecl ;) > const > MyString: AnsiString = 'Hello World'; // this string could also come > frome somewhere else in your library > begin > Result := GetMem(Length(MyString) + 1); > Move(@MyString[1], Result, Length(MyString)); > Result[Length(MyString)] := 0; > end; > > === code end === > > Note: if your MyString is valid through the complete lifetime it could > be used you can also use "Result := PChar(MyString);" instead, but if > your string is e.g. a variable inside the function or a variable inside > another function you must copy its content. > > If you now allocated a PChar using GetMem you add this function as well > and export it from the library: > > === code begin === > > procedure InLibFreeString(aStr: PChar); > begin > FreeMem(aStr); > end; > > === code end === > > One could of course now extend the API with additional checks. E.g. so > that you know that the string was really allocated by the library and > not by e.g. the program using it. But maybe the heap manager already > checks this, I don't know currently. > > Regards, > Sven Yep, Sven, excellent and hyper clear. Hum, i think that this code must go somewhere in wiki. If you agree i will add it into fpc wiki.

I thought that it was mentioned there somewhere already... If nit feel free to add it. That's what a wiki is good for afterall. ^^

Regards,
Sven

Reply by email

Sven Barth
to Fred van Stappen: Hum, to be sure that i understand... type TStringClass = class(TObject) Name: AnsiString;…
"Fred van Stappen" wrote 34 lines
> Note: if your MyString is valid through the complete lifetime it could > be used you can also use "Result := PChar(MyString);" Hum, to be sure that i understand... type TStringClass = class(TObject) Name: AnsiString; //// does not change SomeText: AnsiString; ///// may change.. end; var AStringClass : TStringClass; .... function GetName: PChar; cdecl ; begin result := PChar(AStringClass.Name); end; function GetSomeText: PChar; cdecl ; var MyString: AnsiString ; begin MyString := AStringClass.SomeText ; Result := GetMem(Length(MyString) + 1); Move(@MyString[1], Result, Length(MyString)); Result[Length(MyString)] := 0; end; Is it OK ?

You don't need the MyString variable, you can simply use AStringClass.SomeText. The variable was just for illustrations.

And you should definitely document the results of which of your libraries must be freed and which must not.

Additionally I would suggest to store the pointer values of the allocated PChar results (e.g. TList or specialize TFPGList<PChar>) so that you can use this inside your exported FreeString function to check whether this is indeed a pointer that you need to free.

Regards,
Sven

Reply by email

Fred van Stappen
to Sven Barth
I thought that it was mentioned there somewhere already... If nit feel

free to add it. That's what a wiki is good for afterall. ^^

Hum, never seen... I will add it ASAP ;-)

You don't need the MyString variable, you can simply use AStringClass.SomeText.

=> OK

Show quoted text 5 lines
And you should definitely document the results of which of your libraries must be freed and which must not. Additionally I would suggest to store the pointer values of the allocated PChar results

=> Yep, good idea, i will do it.

One more time, tetra thanks Sven.

Fred

Reply by email

Reinier Olislagers
to Fred van Stappen
Fred van Stappen wrote 6 lines
> I thought that it was mentioned there somewhere already... > If nit feel free to add it. That's what a wiki is good for afterall. ^^ Done. => http://wiki.freepascal.org/shared_library

I think I've spotted a mistake in the wiki.

I've adjusted the description of InLibFreeString according to Sven's previous post:
"And, for freeing the allocated memory, you may add this procedure in the main application : "
=>
"And, for freeing the allocated memory, you may add this procedure in the library, which you can then call from your main application : " and adjusted the rest of the text accordingly...

Of course, please feel free to adjust.

Reply by email

Fred van Stappen
to Reinier Olislagers
Show quoted text 25 lines
Date: Sun, 16 Mar 2014 10:43:17 +0100 From: To: Subject: Re: [fpc-pascal] Library.StringFunction() : PChar => NO On 15/03/2014 12:21, Fred van Stappen wrote: >> I thought that it was mentioned there somewhere already... >> If nit feel free to add it. That's what a wiki is good for afterall. ^^ > > Done. > > => http://wiki.freepascal.org/shared_library I think I've spotted a mistake in the wiki. I've adjusted the description of InLibFreeString according to Sven's previous post: "And, for freeing the allocated memory, you may add this procedure in the main application : " => "And, for freeing the allocated memory, you may add this procedure in the library, which you can then call from your main application : " and adjusted the rest of the text accordingly... Of course, please feel free to adjust.

Many bedankt Harry . ;-)

Reply by email