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

时间:2016-08-30 15:46:59

标签: delphi clang c++builder delphi-10.1-berlin c++builder-10.1-berlin

在一个新的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 - 添加具有上述SetValue函数的Delphi单元

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

一切都是。

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

1 个答案:

答案 0 :(得分:2)

这似乎是BCC32C编译器中的错误。我想它并没有正确地扩展到处理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) ,因为德尔福需要它。

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

10

这是正确的。它首先以40格式推送Extended,然后Extended。请注意,每个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 占用堆栈上的12个字节。

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

40

它首先读取32个单精度浮点Extended并将其存储为[ESP] 10。到现在为止还挺好。但随后它会读取下一个32位单精度浮点[ESP+$0A](仍然可以),但将其存储在[ESP+$0C] ,这显然是错误的(对于Delphi)!它应存储在[ESP+$0C]!这就是为什么第一个值,由[ESP+$0A]处的Pascal函数读取,但由BCC32C在void __fastcall Bla(long double a, long double b) { printf("%Lf %Lf\n", a, b); } 存储,是错误的。

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

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

Extended

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

奇怪的是,如果要调用的函数不是Delphi cdecl函数,而是普通的C ++(Extended)函数,那么BCC32C编译器将存储long double s([ESP+$0C] s)分别位于[ESP]var

变通方法

正如David Heffernan评论的那样,您可以在记录中传递多个扩展名。或者,您可以将它们作为SetVal(10.0, 40.0);参数传递。在这两种情况下,都不像调用> result <- apply(data[, -1], 1, function(x) ifelse(all(is.na(x)), NA, x[!is.na(x)])) > data.frame(a=data[,1], N=result) a N 1 A 1 2 B 2 3 C 3 4 D 4 5 E NA 那么简单。