E2010不兼容的类型,为什么?

Pao*_*ndi 8 delphi unicode types

我收到这个错误:

[DCC Error] JwaStrSafe.pas(2277): E2010 Incompatible types: 'PSTRSAFE_LPWSTR' and 'PSTRSAFE_LPTSTR'
Run Code Online (Sandbox Code Playgroud)

以下是来自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}
Run Code Online (Sandbox Code Playgroud)

我在参数ppszDestEnd上调用StringCchCopyExW时出错.

查看类型定义我明白PSTRSAFE_LPTSTR是STRSAFE_LPTSTR的指针类型,它只是STRSAFE_LPWSTR的别名,为什么PSTRSAFE_LPTSTR和PSTRSAFE_LPWSTR不兼容?

解决方案
感谢大卫的解释,我取而代之

PSTRSAFE_LPTSTR = ^STRSAFE_LPTSTR;
Run Code Online (Sandbox Code Playgroud)

PSTRSAFE_LPTSTR = PSTRSAFE_LPWSTR;
Run Code Online (Sandbox Code Playgroud)

现在代码编译没有错误.

谢谢

Dav*_*nan 5

我可以很容易地在 XE2 中重现这一点,我想它在所有其他版本中的表现都一样。为了简化起见,我将其简化为:

program PointerTypeCompatibility;
{$APPTYPE CONSOLE}
type
  A = Integer;
  B = Integer;
var
  ptA: ^A;
  ptB: ^B;
begin
  ptA := ptB;
end.
Run Code Online (Sandbox Code Playgroud)

这也会产生 E2010。但是,如果启用类型检查指针选项,则代码编译成功。事实上,该编译器选项的文档指出:

在 {$T-} 状态下,除 Pointer 之外的不同指针类型是不兼容的(即使它们是指向相同类型的指针)。在 {$T+} 状态下,指向相同类型的指针是兼容的。


感谢 Ken White 为我指出有用的帮助主题Type Compatibility and Identity。相关的摘录是类型 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.
Run Code Online (Sandbox Code Playgroud)

所以,总结一下:

  • 当类型检查指针被禁用时,如果指针是相同类型的指针是赋值兼容的。
  • 启用类型检查指针时,如果指针指向相同类型,则指针是赋值兼容的。

我不得不承认我对类型检查指针设置背后的历史和推理一无所知,所以我无法解释为什么编译器是这样的。

  • 这可能会有所帮助:[Type Identity](http://docwiki.embarcadero.com/RADStudio/en/Type_Compatibility_and_Identity)。 (3认同)