在一个新的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)。
答案 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
那么简单。