Peter Turner
Peter Turner

Reputation: 11435

Which takes the biggest hit: AnsiString to String or String to AnsiString?

For my purposes, I'm actually truly using ASCII character data (for submitting ASCII text files to the state), so just using unicodestring won't help the end result (I'd still have to convert something).

I've got the option to convert a StrComp function in Delphi 2009 that went from comparing a AnsiString and an PAnsiChar to a UnicodeString and an PAnsiChar.

Val : PAnsiChar
Mask : TEditMask;

....

this is my original code, it's not good

StrComp(PAnsiChar(Mask.EditText), Val);

....

so, I can change it to this:

StrComp(PAnsiChar(AnsiString(MAskEdit.EditText), Val);

or, I can change it to this (extra conversions for 'clarity'):

StrComp(PChar(MAskEdit.EditText), PChar(String(AnsiString(Val))));

I remember Marco Cantu saying, don't do one of these in a loop, I just don't remember which one or why.

Upvotes: 1

Views: 1773

Answers (2)

Arnaud Bouchez
Arnaud Bouchez

Reputation: 43023

If you compile this:

StrComp(PAnsiChar(Mask.EditText), Val);

There is an implicit conversion from the Mask.EditText as UnicodeString into a temporary AnsiString in order to allow the type cast to PAnsiChar. That is your 2nd line:

StrComp(PAnsiChar(AnsiString(MAskEdit.EditText), Val);

But writing

StrComp(PChar(MAskEdit.EditText), PChar(String(AnsiString(Val))));

will let PChar(MAskEdit.EditText) return a PChar, that is a PWideChar, so it will use the other overloaded StrComp function.

In fact, there are two overloaded functions defined since Delphi 2009 in SysUtils.pas:

function StrComp(const Str1, Str2: PAnsiChar): Integer; overload;
function StrComp(const Str1, Str2: PWideChar): Integer; overload;

Both functions won't call the windows API, but will compare the characters one by one, with case sensitivity.

So my advice is that you simply do not use any pointer in your code, but rely on plain string = UnicodeString variables everywhere in your code, and use this function instead:

function CompareStr(const S1, S2: string): Integer;

The comparison will be the same, and there will be no hidden conversion. The issue with having WideChar instead of AnsiChar (i.e. having two times more memory) is nothing compared with the conversion (two WinAPI calls) between unicode and current ansi page. To quote your title, conversion direction does not matter: it is always much slower than no conversion.

If you search about speed, I suspect that Mask.EditText is definitively the bottleneck in your code. This method will send a GDI message, wait for the response of the component, then affect a string with the text. You should better use a temporary variable on stack, if, as I suspect, you are using this Mask.EditText expression in a loop.

Upvotes: 5

Remy Lebeau
Remy Lebeau

Reputation: 595402

The real question is - why are you comparing a UnicodeString to a PAnsiChar instead of updating the PAnsiChar data to Unicode? You should use AnsiChar/AnsiString at the boundaries that interact with legacy data, network connections, etc. All internal processing should be using a single string encoding to avoid these kinds of issues. Convert legacy/network data from Ansi to Unicode when loading the data. Convert from Unicode to Ansi when saving legacy data, sending network data, etc.

Upvotes: 2

Related Questions