在一个新的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 ++中,它被映射为10字节长双精度(对于Win32)。
这似乎是BCC32C编译器中的错误。我猜想它没有适当地扩展以应付Extended
Delphi的需要。
如果您查看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
,然后40
按Extended
格式。请注意,每个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
并将其存储为Extended
at [ESP]
。到现在为止还挺好。但是随后它读取下一个32位单精度浮点数10
(仍然可以),然后将其存储在中[ESP+$0A]
,这显然是错误的(对于Delphi)!它应该存储在[ESP+$0C]
!这就是为什么第一个值是错误的,该值由Pascal函数在读取[ESP+$0C]
,但由BCC32C存储在[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期望10Extended
个字节在堆栈中占据12个字节,而不是BCC32C那样占用10个字节。
足够奇怪的是,如果要调用的函数不是Delphi__fastcall
函数,而是普通的C ++(cdecl
)函数,则BCC32C编译器会将Extended
s(long double
)分别存储在[ESP+$0C]
和中[ESP]
。
正如David Heffernan所说,您可以在一条记录中传递多个扩展名。或者,您可以将它们作为var
参数传递。在这两种情况下,它都不像调用那样简单SetVal(10.0, 40.0);
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句