E2010 Несовместимые типы, почему? - PullRequest
8 голосов
/ 02 декабря 2011

Я получаю эту ошибку:

[DCC Error] JwaStrSafe.pas(2277): E2010 Incompatible types: 'PSTRSAFE_LPWSTR' and 'PSTRSAFE_LPTSTR'

Ниже приведена соответствующая часть кода из JwaStrSafe.pas (из Jedi Api), я компилирую с определенным символом UNICODE:

type

STRSAFE_LPWSTR = PWIDECHAR;
PSTRSAFE_LPWSTR = ^STRSAFE_LPWSTR;

{$IFDEF UNICODE}
  STRSAFE_LPTSTR = STRSAFE_LPWSTR;
  PSTRSAFE_LPTSTR = ^STRSAFE_LPTSTR;
{$ELSE}
  ...
{$ENDIF}

...
//function declaration
function StringCchCopyExW(
  {__out_ecount(cchDest)}pszDest : STRSAFE_LPWSTR;
  {__in}cchDest : size_t;
  {__in}const pszSrc : STRSAFE_LPCWSTR;
  {__deref_opt_out_ecount(pcchRemaining^)}ppszDestEnd : PSTRSAFE_LPWSTR;
  {__out_opt}pcchRemaining : PSize_t;
  {__in}dwFlags : Cardinal) : HRESULT; stdcall; forward; external;

...
//var passed to function
ppszDestEnd : PSTRSAFE_LPTSTR;

...

{$IFDEF UNICODE}
  result := StringCchCopyExW(pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
{$ELSE}
  result := StringCchCopyExA(pszDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
{$ENDIF}

Я получаю сообщение об ошибке при вызове StringCchCopyExW для параметра ppszDestEnd.

Глядя на определение типа, я понимаю, что PSTRSAFE_LPTSTR является типом указателя на STRSAFE_LPTSTR, который является просто псевдонимом STRSAFE_LPWSTR, поэтомуPSTRSAFE_LPTSTR и PSTRSAFE_LPWSTR несовместимы?

Решение
Благодаря объяснению Дэвида я заменил

PSTRSAFE_LPTSTR = ^STRSAFE_LPTSTR;

на

PSTRSAFE_LPTSTR = PSTRSAFE_LPWSTR;

, теперь кодкомпилируется без ошибок.

Спасибо

1 Ответ

4 голосов
/ 02 декабря 2011

Я могу достаточно легко воспроизвести это в XE2, и я думаю, что он будет вести себя так же во всех других версиях. Чтобы упростить это, я сократил это до:

program PointerTypeCompatibility;
{$APPTYPE CONSOLE}
type
  A = Integer;
  B = Integer;
var
  ptA: ^A;
  ptB: ^B;
begin
  ptA := ptB;
end.

Это также производит E2010. Однако, если вы включите опцию проверенные типом указатели , код будет успешно скомпилирован. Фактически документация об этих опциях компилятора гласит:

В состоянии {$ T-} различные типы указателей, отличные от Pointer, несовместимы (даже если они являются указателями на один и тот же тип). В состоянии {$ T +} указатели на один и тот же тип совместимы.


Спасибо Кену Уайту за указание на полезную тему справки Совместимость типов и идентичность . Соответствующими выдержками являются то, что типы T1 и T2 совместимы с назначением , если:

T1 и T2 являются совместимыми типами указателей.

В документации также указывается, что типы совместимы с типами , если:

Оба типа являются (типизированными) указателями на один и тот же тип, и действует директива компилятора {$ T +}.

Итак, это документирует наблюдаемое поведение и приводит меня к следующему примеру:

program PointerTypeCompatibilityTake2;
{$APPTYPE CONSOLE}
{$TYPEDADDRESS OFF}
var
  P1,P2: ^Integer;
  P3: ^Integer;
begin
  P1 := P2;//compiles
  P1 := P3;//E2008 Incompatible types
end.

Итак, подведем итог:

  • Когда указатели с проверкой типа отключены, указатели совместимы по присваиванию, если указатели имеют одинаковый тип.
  • Когда указатели с проверкой типа включены, указатели совместимы по присваиванию, если указатели указывают на один и тот же тип.

Я должен признаться, что не знаю истории и рассуждений о настройке указателя с проверкой типа, поэтому я не могу предложить никакого объяснения, почему компилятор такой, какой он есть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...