从C#调用Delphi 6 DLL导致不同的舍入?

时间:2012-06-06 21:49:36

标签: c# delphi dll dllimport

我在使用delphi舍入时遇到了一些严重的问题(当从c#项目中使用时)并且当值似乎落在.5括号内时它的结果是一致的,即它是向上还是向下舍入???

我创建了一个执行许多操作的delphi DLL。其中一项行动的关键是(例如)

double := Round(double1   * double2);

其中double1 = 1.9且double2 = 225(从文件中获取的值从中读取)

我的计算器上的结果显示它应该是427.5。 delphi DLL中的结果是427.四舍五入,根据Round()

的delphi文档都很好

这些计算的值存储在代表表格的Delphi(我相信的类)中。在上面的情况下像这样

property SRDairy           : Double   read FSRDairy             write FSRDairy;

这个属性属于一堆类,并且像这样被序列化到Delphi DLL中的缓冲区(AOvrFarm是包含所有要序列化的项目的父项,包括我的SRDairy)

procedure GetResultString(AOvrFarm: TdataV6; outputStringBuffer: PChar; var
    bufLen: Integer);
var
  MyStrings : TStringList;
  resultString   : string;
begin
  MyStrings := TStringList.Create;
  try
    AOvrFarm.SavetoStrings(MyStrings);
    resultString := MyStrings.Text;

    if outputStringBuffer = nil then
    begin
      bufLen := Length(resultString) + 1;
    end
    else
    begin
      StrLCopy(outputStringBuffer, PChar(resultString), bufLen - 1);
    end;
  finally
    MyStrings.Free;
  end;
end;

在此DLL中有许多其他属性,表单(类)等。结束时,此文件被序列化为一个字符串,该字符串返回给调用者(c#)应用程序,refoutputStringBuffer使用类似(在delphi中)填充:

  StrLCopy(outputStringBuffer, PChar(resultString), bufLen - 1);

我的问题是当我从c#应用程序调用此DLL时。我得到的结果不是427,它是428.圆满!!!!

德尔福签名:

function ConvertString(fileContents:PChar; fileExt:PChar; var outputStringBuffer:       PChar类型; var outputStringBufferSize:Integer; var errorMsgBuffer:PChar; VAR       errorMsgBufferSize:Integer):WordBool; STDCALL;出口;

我使用c#中的DLL,如:

[DllImport("OvrFileImport.dll",
               CallingConvention = CallingConvention.StdCall,
               CharSet = CharSet.Ansi)]

public static extern bool
        ConvertString(
        string fileContents, 
        string fileExt, 
        ref string refputStringBuffer,
        ref int outputStringBufferSize, 
        ref string errorMsgBuffer, 
        ref int errorMsgBufferSize);

转换字符串调用一次以获取缓冲区大小,然后再次调用填充缓冲区。这是第二次电话,我注意到了差异。当从Test Delphi项目使用相同的DLL时,我得到427(而不是c#428)。

我已经尝试针对任何CPU构建我的c#而只是x86因为我的PC是64位机器而出现了某种cpu 64位问题。

有没有人遇到过这种事情,如果有的话,他们有什么办法吗?

编辑 - 答案

正如David Heffernan所提​​到的,从c#调用DLL时使用的控制字与从另一个Delphi应用程序调用时使用的控制字不同。从c#调用时使用的控制字实际上是639美元。

不幸的是,将控制字设置为$ 1372会导致我的c#app在调试时出现问题,即它导致本地监视窗口显示“由于堆栈溢出状态而无法评估”所有变量的异常。我找到了article - strange floating point results来讨论这个问题,因此改为$ 133F(这解决了浮点差异和c#调试问题)。

代码:

begin
     cw := Get8087CW;
     Set8087CW($133F);
     ....
     finally
        Set8087CW(cw);    

1 个答案:

答案 0 :(得分:2)

1.9在浮点中不能完全表示,而225则完全可以表示。

目前尚不清楚输入数字的来源,但IEEE754算法根本不可能完全执行产品1.9 * 225。您看到的行为与舍入无关,实际上是关于可表示性的。如果您需要完全执行此计算,则需要使用十进制算术而不是浮点。这意味着在Delphi中使用货币类型或在C#中使用小数。

您的不同行为的来源可能是控制浮点寄存器的8087控制字。当您的DLL执行时,从C#调用,控制字将与默认的Delphi设置不同。在DLL的入口点调用Set8087CW($ 1372)以使用默认的Delphi控制字。请记住在从DLL返回之前恢复它。