There are, however, a few caveats one needs to be aware of when mixing string and PChar that he does not mention. This is what I want to cover in this brief article.
The problems mixing string and PChar described here are caused by null characters (or #0 in Delphi syntax). Since Delphi strings have a length counter, It is perfectly legal for them to contain #0. Since PChar are null-terminated, by definition they cannot contain #0.
However, a few Delphi routines that seem to operate on strings internally actually operate on PChar. They will therefore not work as expected when the string they are given contains #0.
You cannot replace #0 in a string
If you call StringReplace to replace #0, it simply won’t work.
function RemoveNull(AInput: string): string; begin Result := StringReplace(AInput, #0, '', [rfReplaceAll]); // Won’t work end;
StrPCopy stops at #0
The StrPCopy routine takes a string as an input and copies it into a PChar. I used to use this routine in a TStringBuilder-like class which used a PChar to refer to an internal buffer containing the string being built. It also had a length counter, so one would not have to scan the PChar to figure out its length.
But even though StrPCopy takes a string as its input and could thus have access to its length, it does not copy all character, but stops at the first #0.
Beware of implicit conversions
Since the compiler supports implicitly converting between PChar and string, you will often get away with passing a PChar where a routine takes a string parameter. The compiler will just generate a temporary string from the PChar and pass that instead.
Hence, this code will compile and work just fine:
function GetSubstring(AInput: PChar; AStart, ASubstringLength: Integer): string; begin Result := Copy(AInput, AStart, ASubstringLength); // Works, but is slow end;
Unfortunately, it has horrible performance, because the compiler needs to know the length of the PChar in order to built that temporary string. And the only way to figure out the length of a PChar is to check every character until the first #0.