Conversion de pointeurs et de tableaux de C ++ en Delphi

J’essaie d’utiliser la bibliothèque ANN (le plus proche voisin approximatif ) (le .dll) dans mon code Delphi. La bibliothèque est écrite en C ++, et bien que les types de données soient assez simples, je rencontre quelques problèmes.

J’ai utilisé h2pas pour convertir le fichier d’en-tête C ++ dans la mesure du possible. J’ai fini avec les types de données suivants (C ++ à gauche, Delphi à droite):

 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; 

Pour commencer, je veux porter avec succès l’échantillon fourni avec la bibliothèque ANN . Le code C ++ de cet exemple est lié ici sans commentaires (si vous voulez les commentaires, téléchargez simplement la bibliothèque à partir de la page Web d’ANN).

Plus précisément encore, voici l’extrait qui me pose problème (code C ++ ..):

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

Un membre de stackoverflow m’a aidé avec une conversion partielle de la fonction readPt – mais je ne suis pas sûr qu’elle soit complètement correcte (code 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; 

Voici ma tentative infructueuse d’implémentation de cette boucle While dans Delphi (code non pertinent omis):

 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; 

Lorsque readPt(BinStream, dataPts[nPts]); une erreur de segmentation readPt(BinStream, dataPts[nPts]); à readPt(BinStream, dataPts[nPts]);

Je serai extrêmement reconnaissant si quelqu’un prend le temps de m’aider ici!

Edit: Dans le cas où la fonction C ++ de annAllocPts() est importante .. la voici:

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

Et voici comment je l’ai implémenté:

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

Edit 2: Je n’arrive toujours pas à remplir correctement le stream d’entrée (je pense) …

 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; 

Votre code appelle la fonction DLL pour allouer un tableau de 1000 tableaux de Double à 2 éléments. Ensuite, vous remplissez un stream avec 1001 octets . Vous essayez de remplir 16 000 octets de stockage avec seulement 1001 octets de données.

De plus, les données que vous mettez dans le stream ne forment de toute façon pas de valeurs Double significatives.

De plus, votre version de readPt est incorrecte. Vous affectez inStr.Size place de la variable locale Size . Le compilateur aurait dû vous avertir que Size était utilisé sans être initialisé. Votre code a pour effet de tronquer le stream d’entrée à la longueur d’un segment de tableau, puis de tenter de lire un nombre inconnu d’octets dans le stream. Utilisez la version que vous avez obtenue de votre autre question .

Le code dans readPt () est correct. Mais il lit plus d’un double d’un coup, comme dans l’exemple C ++ de l’autre question.

Votre problème est que vous écrivez maxPts (= 1000) doubles dans le stream de mémoire, mais ensuite, dans une boucle (de MaxPts = 1000 itérations), vous lisez dim (= 2) double par itération (readPt lit dimcoords en une fois). , vous essayez donc de lire 1000 * 2 ANNcoords et de manquer de données avant d’atteindre la fin. Vous devriez vérifier la valeur de retour de readPt () dans la boucle et casser si elle est fausse:

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

Bien sûr, vous pouvez également écrire des éléments dim * maxPts dans le stream de mémoire.