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

9

我遇到了这个错误:

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

以下是来自Jedi Api 中的 JwaStrSafe.pas 代码的相关部分,我正在使用符号 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_LPTSTR只是STRSAFE_LPWSTR的别名,为什么PSTRSAFE_LPTSTR和PSTRSAFE_LPWSTR不兼容?

解决方案
感谢David的解释,我进行了替换。

PSTRSAFE_LPTSTR = ^STRSAFE_LPTSTR;

使用

PSTRSAFE_LPTSTR = PSTRSAFE_LPWSTR;

现在这段代码可以成功编译。

谢谢。


3
你使用的是哪个版本的 Delphi? - Mason Wheeler
1个回答

5
我可以在XE2中轻松重现这个问题,我想在所有其他版本中它的表现都是相同的。为了简化,我将其缩减为以下内容:
program PointerTypeCompatibility;
{$APPTYPE CONSOLE}
type
  A = Integer;
  B = Integer;
var
  ptA: ^A;
  ptB: ^B;
begin
  ptA := ptB;
end.

这也会产生E2010错误。但是,如果您启用类型检查指针选项,则代码可以成功编译。实际上,该编译器选项的文档说明如下:

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


感谢Ken White向我推荐了有用的帮助主题类型兼容性和标识。相关摘录是,如果类型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.

因此,总结一下:

  • 当禁用类型检查指针时,如果指针是相同类型,则指针可互相赋值。
  • 当启用类型检查指针时,如果指针指向相同类型,则指针可互相赋值。

我必须承认我对类型检查指针设置的历史和原因一无所知,因此我无法解释编译器为什么会这样。


3
这可能有所帮助:类型一致性与相等性 - Ken White
不用谢。你已经在没有链接的情况下付出了很多努力,我不想使用它并窃取你的工作。 :) 做得好 - +1。 - Ken White
@Ken 谢谢。如果您能添加一个有价值的答案,我会非常高兴的;-) - David Heffernan
$TYPEDADDRESS 帮助页面中引用的一段话:_在 {$T-} 状态下,除了指针类型之外的不同指针类型是不兼容的(即使它们指向相同的类型)_。 - Paolo Biondi
在XE5中,这个(在{$R *.DFM}之后放置{$TYPEDADDRESS OFF})解决了在使用BASS dll并执行BASS_ChannelSetSync时的语法错误。 - user30478

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接