首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用C DLL使用delphi类型的问题

用C DLL使用delphi类型的问题
EN

Stack Overflow用户
提问于 2014-06-13 16:41:02
回答 1查看 175关注 0票数 3

我正在尝试使用用C编写的.dll (尽管它封装在matlab .ddl上)。

我试图使用的函数在C中定义为:

代码语言:javascript
运行
复制
 __declspec(dllexport) int ss_scaling_subtraction(double* time, double** signals, double* amplitudes, int nSamples, int nChannels, double* intensities);

除其他外,.dll需要一个二维数组--当我尝试使用:

代码语言:javascript
运行
复制
Array of array of double

在声明中,编译器给出了一个错误,因此我定义了自己的数据类型:

代码语言:javascript
运行
复制
T2DArray = Array of array of double;

我在如下所示的单元中初始化.dll函数:

代码语言:javascript
运行
复制
 function ss_scaling_subtraction(const time: array of double; const signals: T2DArray; const amplituides : array of double; const nSamples: integer;const nChannels: integer; var intensities: array of double) : integer ; cdecl; external 'StirScanDLL.dll';

但是,当调用此函数时,我会从.dll获得一个访问冲突。

创建新的数据类型

代码语言:javascript
运行
复制
T1DArray = array of double

和变化

代码语言:javascript
运行
复制
Array of double

代码语言:javascript
运行
复制
T1DArray

在声明中似乎让事情运行,但结果仍然不正确。

我在这里读到,将delphi数据类型传递给用不同语言编写的..dll可能是危险的,所以我认为这可能会导致问题。

但是,当我必须首先正确声明函数时,如何不用delphi数据类型呢?!

额外的信息,我已经打开了matlab运行时编译器库并打开了StirScanDLL.dll的入口点

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-13 18:08:39

这里的基本问题是二进制互操作失配。简单地说,指向数组的指针与Delphi打开的数组参数在二进制级别上是不一样的。虽然它们都在语义上表示数组,但二进制表示不同。

C函数声明如下:

代码语言:javascript
运行
复制
__declspec(dllexport) int ss_scaling_subtraction(
    double* time, 
    double** signals, 
    double* amplitudes, 
    int nSamples, 
    int nChannels, 
    double* intensities
);

在Delphi中这样声明您的函数:

代码语言:javascript
运行
复制
function ss_scaling_subtraction(
    time: PDouble; 
    signals: PPDouble; 
    amplitudes: PDouble; 
    nSamples: Integer;
    nChannels: Integer; 
    intensities: PDouble
): Integer; cdecl; external 'StirScanDLL.dll';

如果您发现没有声明PPDouble,请这样定义它:

代码语言:javascript
运行
复制
type
  PPDouble = ^PDouble;

也就是说,指向指向双的指针。

现在剩下的就是调用函数。在Delphi中将数组声明为动态数组。如下所示:

代码语言:javascript
运行
复制
var
  time, amplitudes, intensities: TArray<Double>; 
  signals: TArray<TArray<Double>>; 

如果您有一个旧的预泛型Delphi,那么声明一些类型:

代码语言:javascript
运行
复制
type
  TDoubleArray = array of Double;
  T2DDoubleArray = array of TDoubleArray;

然后用适当的类型声明变量。

接下来,您需要分配数组,并填充从调用方传递到被调用方的任何数据。

代码语言:javascript
运行
复制
SetLength(time, nSamples); // I'm guessing here as to the length
SetLength(signals, nSamples, nChannels); // again, guessing

最后,是时候调用该函数了。现在,Delphi的优秀设计人员将动态数组作为指向第一个元素的指针进行存储。这意味着它们是一个简单的抛弃,而不是被用作参数。

代码语言:javascript
运行
复制
retval := ss_scaling_subtraction(
   PDouble(time),
   PPDouble(signals),
   PDouble(amplitudes),
   nSamples,
   nChannels,
   PDouble(intensities)
);

请注意,这里看到的动态数组的转换确实依赖于实现细节。因此,有些人可能会争辩说,使用它会更好,例如,@time[0]等用于一维数组。并为振幅创建一个PDouble数组,并复制内部数组的第一个元素的地址。就我个人而言,我习惯于依赖这个实现细节。它确实使编码变得更简单了。

最后一个建议。互操作可能很棘手。很容易出错。如果你搞错了,代码就会编译,但在运行时会死得很惨。带有隐秘的错误信息。会让人抓挠头的。

所以,从最简单的接口开始。接收标量参数的函数。比如说,接收一个整数,然后返回一个整数。证明你能做到。然后转到浮点标量。然后是一维数组。最后是二维阵列。一路上的每一步,都会增加复杂性。当您遇到一个问题时,您就会知道它是最近添加的参数。

你还没采取那种方法。在你的第一次尝试中,你直接去了杀戮并实现了所有的东西。当它失败的时候,你不知道该去哪里找。将一个问题分解成小块,然后从这些较小的部分中构建出更复杂的问题。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24210128

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档