3 Stimmen

Umwandlung von Delphi 2009/2010 String-Literalen in PAnsiChar

Die Frage ist also, ob String-Literale (oder const-Strings) in Delphi 2009/2010 direkt als PAnsiChar gecastet werden können oder ob sie zuerst in AnsiString gecastet werden müssen, damit dies funktioniert?

Der Hintergrund ist, dass ich Funktionen in einer Legacy-DLL mit einer C-Schnittstelle aufrufe, die einige Funktionen hat, die Char-Zeiger im C-Stil erfordern. In der Vergangenheit (vor Delphi 2009) Code wie der folgende funktionierte wie ein Charme (wo die param an die C-DLL-Funktion ist ein LPCSTR):

entweder:

LegacyFunction(PChar('Fred'));

または

const
  FRED = 'Fred';
...
LegacyFunction(PChar(FRED));

Daher habe ich beim Wechsel zu Delphi 2009 (und jetzt 2010) den Aufruf in diesen geändert:

LegacyFunction(PAnsiChar('Fred'));

または

const
  FRED = 'Fred';
...
LegacyFunction(PAnsiChar(FRED));

Dies scheint zu funktionieren, und ich erhalte die richtigen Ergebnisse aus dem Funktionsaufruf. Es gibt jedoch eine deutliche Instabilität in der Anwendung, die vor allem beim zweiten oder dritten Mal durch den Code auftritt, der die Legacy-Funktionen aufruft (was vor dem Wechsel zur Version 2009 der IDE nicht der Fall war). Bei der Untersuchung des Problems habe ich festgestellt, dass das native String-Literal (und const-String) in Delphi 2009/2010 ein Unicode-String ist, so dass mein Cast möglicherweise fehlerhaft war. Beispiele hier und anderswo scheinen darauf hinzuweisen, dass dieser Aufruf eher wie folgt aussehen sollte:

LegacyFunction(PAnsiChar(AnsiString('Fred')))

Was mich verwirrt ist, dass mit dem Code oben in den zweiten Beispielen, Casting der String-Literal direkt zu einem PAnsiChar keine Compiler-Warnungen erzeugt. Würde ich statt eines String-Literal eine String-Var casten, würde ich eine verdächtige Cast-Warnung erhalten (und der String würde verstümmelt werden). Dies (und die Tatsache, dass die Zeichenfolge in der DLL verwendbar ist) führt mich zu glauben, der Compiler tut einige Magie, um die Zeichenfolge-Literal als den beabsichtigten String-Typ korrekt zu interpretieren. Ist es das, was passiert, oder ist die doppelte Umwandlung (zuerst in AnsiString, dann in PAnsiChar) wirklich notwendig und das Fehlen dieser Umwandlung in meinem Code der Grund für die schwer aufzuspürende Instabilität? Und gilt die gleiche Antwort auch für const-Strings?

9voto

Barry Kelly Punkte 40566

Bei typinfizierten Konstanten (nur initialisierbar aus Literalen) ändert der Compiler den eigentlichen Text zur Compilierzeit und nicht zur Laufzeit. Das bedeutet, dass er kennt ob bei der Konvertierung Daten verloren gehen oder nicht, so dass Sie nicht gewarnt werden müssen, wenn dies nicht der Fall ist.

5voto

Krystian Bigaj Punkte 1286

Die Worte von Barry Kelly und Mason Wheeler "visualisieren":

const
  FRED = 'Fred';

var
  p: PAnsiChar;
  w: PWideChar;
begin
  w := PWideChar(Fred);
  p := PAnsiChar(Fred);

In ASM:
Unit7.pas.32: w := PWideChar(Fred);
00462146 BFA4214600       mov edi,$004621a4     
// no conversion, just a pointer to constant/"-1 RefCounted" UnicodeString

Unit7.pas.33: p := PAnsiChar(Fred);
0046214B BEB0214600       mov esi,$004621b0
// no conversion, just a pointer to constant/"-1 RefCounted" AnsiString

Wie Sie sehen können, gibt es in beiden Fällen, PWideChar/PChar(FRED) und PAnsiChar(FRED), keine Konvertierung und der Delphi-Compiler erzeugt zwei konstante Strings, einen AnsiString und einen UnicodeString.

4voto

Mason Wheeler Punkte 79858

Konstanten, einschließlich String-Literalen, sind standardmäßig untypisiert, und der Compiler passt sie in das Format ein, das in dem Kontext, in dem sie verwendet werden, funktioniert. Solange keine Nicht-ANSI-Zeichen in Ihrem String-Literal enthalten sind, wird der Compiler in dieser Situation keine Probleme haben, den String als ANSI statt als Unicode zu erzeugen.

1voto

AlexV Punkte 21793

Wie Mason Wheeler betont, ist alles in Ordnung, solange Sie nicht nicht-ANSI-Zeichen in Ihrer Zeichenkette const. Wenn Sie Dinge haben wie:

const FRED = 'Frédérick';

Ich bin mir ziemlich sicher, dass Delphi 2009/2010 entweder Zeichensatz-Hinweise ausgibt (und automatisch eine String-Konvertierung durchführt - daher der Hinweis) oder beim Vergleich scheitert ("Frédérick" ist in ISO-8859-1 anders als in UTF-16).

Wenn Sie "spezielle" Zeichen in Ihren Konstanten haben können, müssen Sie die Stringkonvertierung aufrufen.

Hier sind einige grundlegende Beispiele mit TStringList:

TStringList.SaveToFile(DestFilename, TEncoding.GetEncoding(28591)); //ISO-8859-1 (Latin1)
TStringList.SaveToFile(DestFilename, TEncoding.UTF8);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X