Приведение Delphi 2009/2010 строковых литералов к PAnsiChar - PullRequest
3 голосов
/ 05 января 2010

Таким образом, вопрос заключается в том, могут ли строковые литералы (или константные строки) в Delphi 2009/2010 напрямую передаваться как PAnsiChar, или им сначала нужно дополнительное приведение к AnsiString, чтобы это работало?

Исходным фоном является то, что я вызываю функции в устаревшей DLL с интерфейсом C, который имеет некоторые функции, для которых требуются указатели символов в стиле C. В прошлом (до Delphi 2009) код, подобный следующему, работал как шарм (где параметром функции C DLL является LPCSTR):

либо:

LegacyFunction(PChar('Fred'));

или

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

Итак, при переходе на Delphi 2009 (а теперь и в 2010 году) я изменил вызов так:

LegacyFunction(PAnsiChar('Fred'));

или

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

Кажется, это работает, и я получаю правильные результаты от вызова функции. Однако в приложении существует определенная нестабильность, которая, по-видимому, возникает в основном во второй или третий раз в коде, который вызывает унаследованные функции (которого не было до перехода на версию IDE 2009 года). Исследуя это, я понял, что нативный строковый литерал (и константная строка) в Delphi 2009/2010 - это строка в Юникоде, поэтому мое приведение могло быть ошибочным. Примеры здесь и в других местах указывают на то, что этот вызов должен выглядеть примерно так:

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

Что меня смущает, так это то, что при приведенном выше коде во втором примере приведение строкового литерала непосредственно к PAnsiChar не генерирует никаких предупреждений компилятора. Если бы вместо строкового литерала я приводил строковую переменную, я получал бы подозрительное предупреждение о приведении (и строка была бы искажена). Это (и тот факт, что строку можно использовать в DLL) заставляет меня поверить, что компилятор делает некоторую магию, чтобы правильно интерпретировать строковый литерал как предполагаемый тип строки. Это то, что происходит, или двойное приведение (сначала к AnsiString, затем к PAnsiChar) действительно необходимо, и отсутствие этого в моем коде является причиной трудной для отслеживания нестабильности? И остается ли такой же ответ верным и для константных строк?

Ответы [ 4 ]

9 голосов
/ 05 января 2010

Для констант с выводом типа (только инициализируемых из литералов) компилятор изменяет фактический текст во время компиляции, а не во время выполнения. Это означает, что знает , теряет ли преобразование данные, поэтому не нужно предупреждать вас, если нет.

5 голосов
/ 05 января 2010

Чтобы «визуализировать» слова Барри Келли и Мейсона Уилера:

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

Как вы можете видеть в обоих случаях PWideChar / PChar (FRED) и PAnsiChar (FRED), преобразование не выполняется, и компилятор Delphi создает 2 постоянные строки, одну AnsiString и одну UnicodeString.

4 голосов
/ 05 января 2010

Константы, включая строковые литералы, по умолчанию не типизированы, и компилятор поместит их в любой формат, который работает в контексте, в котором вы их используете. Пока в строковом литерале нет символов, отличных от ANSI, В этой ситуации у компилятора не возникнет проблем с генерацией строки в формате ANSI вместо Unicode.

1 голос
/ 05 января 2010

Как указывает Мейсон Уилер, все в порядке, если у вас нет символов не-ANSI в вашей строковой константе. Если у вас есть такие вещи, как:

const FRED = 'Frédérick';

Я почти уверен, что Delphi 2009/2010 либо выдаст подсказки кодировки (и автоматически применяет преобразование строк - таким образом подсказку), либо не сравнится («Frédérick» отличается в ISO-8859-1 от UTF-16) .

Если в ваших константах могут быть «специальные» символы, вам нужно вызвать преобразование строки.

Вот несколько основных примеров с TStringList:

TStringList.SaveToFile(DestFilename, TEncoding.GetEncoding(28591)); //ISO-8859-1 (Latin1)
TStringList.SaveToFile(DestFilename, TEncoding.UTF8);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...