指针和数组从c++到Delphi的转换

Conversion of pointers and arrays from C++ to Delphi

本文关键字:Delphi 转换 c++ 数组 指针      更新时间:2023-10-16

我试图在我的Delphi代码中使用ANN(近似近邻)库(.dll)。该库是用c++编写的,尽管数据类型相当简单,但我还是遇到了一些麻烦。

我使用h2pas转换c++头文件,只要我能得到它。我最终得到了以下数据类型(c++在左边,Delphi在右边):

enum ANNbool {ANNfalse = 0, ANNtrue = 1}; --> ANNbool = longint;                
typedef double  ANNcoord;                 --> ANNcoord = double;                
typedef double  ANNdist;                  --> ANNdist = double;                 
typedef int     ANNidx;                   --> ANNidx = longint;                 
typedef ANNcoord* ANNpoint;               --> ANNpoint = ^ANNcoord;             
typedef ANNpoint* ANNpointArray;          --> ANNpointArray = ^ANNpoint;        
typedef ANNdist*  ANNdistArray;           --> ANNdistArray = ^ANNdist;          
typedef ANNidx*   ANNidxArray;            --> ANNidxArray = ^ANNidx;

对于初学者,我想成功地移植ANN库中包含的示例。这个示例的c++代码链接在这里,没有注释(如果你想要注释,只需从ANN的网页下载库)。

更具体地说,这里是我遇到麻烦的摘录(c++代码…):

...
while (nPts < maxPts && readPt(*dataIn, dataPts[nPts]))  nPts++;
...
bool readPt(istream &in, ANNpoint p)
{
 for (int i = 0; i < dim; i++) {
 if(!(in >> p[i])) return false;
 }
 return true;
}

stackoverflow上的一个成员帮助我对readPt函数进行了部分转换-但我不确定它是否完全正确(Delphi代码..):

function readPt(inStr: TStream; p: ANNpoint): boolean;
var
  Size: longint; // number of bytes to read
begin
  inStr.Size := SizeOf(ANNcoord) * dim;
  Result := inStr.Read(p^, Size) = Size;
end; 

这是我在Delphi中实现while循环的不成功尝试(省略了无关的代码):

var
  dataPts: AnnPointArray;
  BinStream: TMemoryStream;    
  dim,maxPts,nPts: LongInt;

begin
  dim := 2; 
  maxPts := 1000;  
  dataPts := annAllocPts(maxPts, dim);      
  //GENERATE TStream data
  ///////////////////////////
  BinStream := TMemoryStream.Create;
  BinStream.SetSize(1001);
  for nPts := 0 to 1000 do
  begin
    BinStream.Write(nPts, 1);
  end;                       
  BinStream.Position := 0
  ///////////////////////////                     
  nPts:=0;
  while nPts < maxPts do
  begin
    readPt(BinStream, dataPts[nPts]);
    nPts:=nPts+1;
  end;  
end;   

当我尝试运行这个时,我在readPt(BinStream, dataPts[nPts]);

处得到分段错误如果有人愿意花时间来帮助我,我将非常感激!

编辑:如果annAllocPts()的c++函数很重要…

ANNpointArray annAllocPts(int n, int dim)       // allocate n pts in dim
{
    ANNpointArray pa = new ANNpoint[n];         // allocate points
    ANNpoint      p  = new ANNcoord[n*dim];     // allocate space for coords
    for (int i = 0; i < n; i++) {
        pa[i] = &(p[i*dim]);
    }
    return pa;
}

我是这样实现的:

function annAllocPts(n: longint; dim: longint): ANNpointArray cdecl;
  external 'ANN.dll' index 33;     

编辑2:我仍然有问题正确填写输入流(我认为)…

var
 ThisDouble: Double;
begin
  binstream := TMemoryStream.Create;
  ThisDouble :=1.001;
  for nPts := 0 to maxPts*dim do
  begin
    binstream.Write(ThisDouble,SizeOf(ThisDouble));
  end;
  BinStream.Position := 0;
  nPts:=0;
  while nPts < maxPts do
  begin
   if not readPt(BinStream, dataPts[nPts]) then
    Break;
  nPts:=nPts+1;
end;                    

您的代码调用DLL函数来分配1000个双元素数组。然后用1001 字节填充流。您试图用1001字节的数据填充16000字节的存储空间。

此外,你放入流中的数据不会形成有意义的Double值。

还有,你的版本的readPt是错误的。您正在分配inStr.Size而不是本地Size变量。编译器应该警告您没有初始化就使用了Size。您的代码会将输入流截断为一个数组段的长度,然后尝试从流中读取未知数量的字节。使用你从另一个问题中得到的版本

readPt()中的代码是正确的。但是它一次读取多个double,就像另一个问题中的c++示例一样。

你的问题是,你写maxPts(=1000)双精度到内存流,但然后,在一个循环(maxPts =1000迭代),你读dim(= 2)双精度每次迭代(readPt读取dim anncoord在一次),所以你尝试读1000*2 anncoord和耗尽数据之前,你到达结束。您应该检查readPt()在循环中的返回值,如果返回值为false则中断:

nPts:=0;
while nPts < maxPts do
begin
  if not readPt(BinStream, dataPts[nPts]) then
    Break;
  nPts:=nPts+1;
end;

当然,也可以将dim * maxPts项写入内存流。