Преобразование указателей и массивов из C ++ в Delphi - PullRequest
1 голос
/ 17 августа 2011

Я пытаюсь использовать библиотеку ANN ( приблизительный ближайший сосед ) (.dll) в моем коде Delphi.Библиотека написана на 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 ++ code ..):

...
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; 

Вот моя неудачная попытка реализовать этот цикл while в Delphi (нерелевантный код опущен):

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]);

Я буду чрезвычайно признателен, если кто-нибудь найдет время, чтобы помочь мне здесь!

Редактировать: В случае, если важна функция C ++ для annAllocPts() .. вот она:

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;                    

Ответы [ 2 ]

4 голосов
/ 17 августа 2011

Ваш код вызывает функцию DLL для выделения массива из 1000 2-элементных массивов Double.Затем вы заполняете поток 1001 байт .Вы пытаетесь заполнить 16000 байт памяти только 1001 байтом данных.

Кроме того, данные, которые вы помещаете в поток, в любом случае не образуют значимых значений Double.

Также, ваша версия readPt неверна.Вы назначаете inStr.Size вместо локальной переменной Size.Компилятор должен был предупредить вас, что Size был использован без инициализации.Ваш код позволяет обрезать входной поток до длины одного сегмента массива, а затем пытаться прочитать неизвестное количество байтов из потока.Используйте версию, полученную из вашего другого вопроса .

1 голос
/ 17 августа 2011

Код в readPt () правильный.Но он читает более одного двойного за один раз, точно так же как пример C ++ в другом вопросе.

Ваша проблема в том, что вы записываете maxPts (= 1000) удваивается в поток памяти, но затем в цикле(из MaxPts = 1000 итераций) вы читаете dim (= 2) удваивается за одну итерацию (readPt считывает dim ANNcoords за один раз), поэтому вы пытаетесь прочитать 1000 * 2 ANNcoords и исчерпать данные, прежде чем достигнете конца.Вам следует проверить возвращаемое значение readPt () в цикле и прервать его, если оно ложно:

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

Конечно, вы также можете записать элементы dim * maxPts в поток памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...