2

在一个新的 Win32 项目中,我有以下 Delphi 函数:

procedure SetValue(value1, value2 : Extended);
begin
end;

在同一个项目中,但来自 C++ 单元,我调用此函数:

SetValue(10, 40);

当我value1使用 BCC32C (CLang) 编译时检查时,我得到 1.68132090507504896E-4932,这是不正确的。

用 BCC32(经典)编译,我得到 10。

在这两种情况下,第二个参数都是 40。

似乎Extended值和参数堆栈加载存在问题。

我使用 RAD Studio 10.1 Berlin。

我该如何解决这个问题?

更新

我没有包含声明,因为 hpp 是在编译时自动创建的。无论如何,声明是:

extern DELPHI_PACKAGE void __fastcall SetValue(System::Extended value1, System::Extended value2);

要复制项目:

1-在 Rad Studio 中创建一个 C++ 项目

2-用上面的SetValue函数添加一个Delphi单元

3-从 C++ 单元,使用 #include 添加 hpp 标头并调用 SetValue

这是全部。

我需要使用扩展类型。我正在使用外部 Delphi 库,因此无法更改类型。上面的代码是对问题的简化。实际上,问题在于调用该库的函数,该函数在参数中使用了 Extended。Extended 是 Delphi 中的本机类型,但在 C++ 中它映射为 long double,10 字节(对于 Win32)。

4

1 回答 1

2

这似乎是 BCC32C 编译器中的错误。我猜它没有正确扩展以处理ExtendedDelphi 需要它。

如果您查看 CPU 窗口,则 BCC32 编译器会生成:

File5.cpp.14: SetVal(10.0L, 40.0L);
00401B8F 6802400000       push $00004002
00401B94 68000000A0       push $a0000000
00401B99 6A00             push $00
00401B9B 6804400000       push $00004004
00401BA0 68000000A0       push $a0000000
00401BA5 6A00             push $00
00401BA7 E80C000000       call Unit12::SetVal(long double,long double)

这是正确的。它首先推送10,然后40Extended格式推送。请注意,每个Extended占用堆栈上的 12 个字节。

但现在看看 BCC32C 编译器的输出:

File5.cpp.14: SetVal(10.0L, 40.0L);
00401B5D 89E0             mov eax,esp
00401B5F D90554F14E00     fld dword ptr [$004ef154]
00401B65 DB38             fstp tbyte ptr [eax]
00401B67 D90558F14E00     fld dword ptr [$004ef158]
00401B6D DB780A           fstp tbyte ptr [eax+$0a]
00401B70 E81F000000       call Unit12::SetVal(long double,long double)
00401B75 83EC18           sub esp,$18

它首先读取 32 个单精度浮点数40并将其存储为Extendedat [ESP]。到目前为止,一切都很好。但是随后它读取下一个 32 位单精度浮点数10(仍然可以),然后将其存储在[ESP+$0A],这显然是错误的(对于 Delphi)!它应该存储在[ESP+$0C]! 这就是为什么Pascal 函数在 处读取但由 BCC32C 在 处存储的第一个值是错误的。[ESP+$0C][ESP+$0A]

所以这似乎是一个错误。报告为https://quality.embarcadero.com/browse/RSP-15737

请注意,这是 BCC32C 推送和期望此类值的正常方式。在同一模块中的 C++ 函数中,即也用 BCC32C 编译,这很好用:

void __fastcall Bla(long double a, long double b)
{
    printf("%Lf %Lf\n", a, b);
}

但是 Delphi 期望 10 字节Extended占用堆栈上的 12 字节,而不是像 BCC32C 那样的 10 字节。

奇怪的是,如果要调用的函数不是 Delphi__fastcall函数,而是普通的 C++ ( cdecl) 函数,BCC32C 编译器会将Extendeds ( long doubles) 分别存储在[ESP+$0C][ESP]中。

解决方法

正如 David Heffernan 评论的那样,您可以在记录中传递多个扩展。或者,您可以将它们作为var参数传递。在这两种情况下,它都不像调用那么简单SetVal(10.0, 40.0);

于 2016-08-30T21:26:58.213 回答