使用扩展参数调用 Delphi 函数时出现 C++ 错误

C++ error when calling a Delphi function with Extended parameters

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

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

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

SetValue(10, 40);

当我在使用 BCC32C (CLang) 编译时检查 value1 时,我得到 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-添加一个Delphi单元,上面的SetValue函数

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

就这些了。

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

这似乎是 BCC32C 编译器中的一个错误。我猜它没有正确扩展以处理 Extended,因为 Delphi 需要它。

如果查看 CPU window,则 BCC32 编译器生成:

File5.cpp.14: SetVal(10.0L, 40.0L);
00401B8F 6802400000       push [=10=]004002
00401B94 68000000A0       push $a0000000
00401B99 6A00             push [=10=]
00401B9B 6804400000       push [=10=]004004
00401BA0 68000000A0       push $a0000000
00401BA5 6A00             push [=10=]
00401BA7 E80C000000       call Unit12::SetVal(long double,long double)

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

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

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

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

所以这似乎是一个错误。报告为 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+[=23=]C][ESP] 中。

解决方法

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

那样简单