我有一个C++ DLL (64位),它接受指向结构的双指针(即指向结构数组的指针)作为输入。该函数动态分配结构数组,然后填充每个结构元素(元素包括:整数、浮点数、双精度数、静态数组、另一个结构和动态分配的数组)。
我已经创建了一个python类来模拟结构(所有数据元素)。但是,当我调用C++函数- CreateROIs( ..)-从python中,我得到了结构中某些元素的垃圾/错误值。
例如,我将获取ppMem.spic=24609435234
有趣是,如果我将相同的数据结构传递回C++ DLL并打印出C++中的元素,它们仍然是正确的(下面没有为这一部分提供函数/代码)。
我假设这是在64位python和C++ DLL之间移动数据时数据类型(双精度/浮点数)的问题。或者可能对结构没有连续的内存?我似乎找不到它...无论如何,任何帮助都是非常感谢的!
这是我的代码,感谢你的帮助!
C++ DLL代码:
// TriangleMesh struct where mesh is defined by vertices connected via triangles
// <summary>
extern "C"
struct MyDLL_API TriangleMesh
{
int nbrVertices;
int nbrTriangles;
float* vertices;
int* triangles;
};
extern "C"
struct MyDLL_API ROI
{
double xmm;
double ymm;
double zmm;
double diameter;
double level;
double volume;
double threshold;
int isMesh;
double mVol;
double mass;
double meanD;
double dve;
double dla;
double dsa;
double dla3D;
double spike;
float sphere;
float lais[6];
float sais[6];
float la3D[6];
TriangleMesh mesh;
};
extern "C" MyDLL_API
void CreateROIs(ROI** ppMem, int* NumROIs);
void CreateROIs(ROI** ppMem, int* NumROIs)
{
*ppMem = (ROI *)malloc(sizeof(ROI) * (*NumROIs));
for (int i = 0; i < *nbrNodules; i++)
{
(*ppMem)[i].xmm = double(i + 1.0);
(*ppMem)[i].ymm = double(i + 1.0);
(*ppMem)[i].zmm = double(i + 1.0);
(*ppMem)[i].diameter = double(i + 1.0);
(*ppMem)[i].level = double(i + 1.0);
(*ppMem)[i].volume= double(i + 1.0);
(*ppMem)[i].threshold = double(i + 1.0);
(*ppMem)[i].mVol= double(i + 1.0);
(*ppMem)[i].mass = double(i + 1.0);
(*ppMem)[i].meanD= double(i + 1.0);
(*ppMem)[i].dve = double(i + 1.0);
(*ppMem)[i].dla = double(i + 1.0);
(*ppMem)[i].dsa = double(i + 1.0);
(*ppMem)[i].dla3D = double(i + 10.0);
(*ppMem)[i].spike = double(i + 1.0);
(*ppMem)[i].sphere = double(i + 1.0);
int arr_size = sizeof((*ppMem)[i].longAxis3D) / sizeof((*ppMem)[i].longAxis3D[0]);
for (int j = 0; j < arr_size; j++)
{
float val = arr_size * i + j;
(*ppMem)[i].lais[j] = val;
(*ppMem)[i].sais[j] = val;
(*ppMem)[i].la3D[j] = val;
}
(*ppMem)[i].meshWasCreatedByDll = int(i+1);
(*ppMem)[i].segMesh.nbrVertices = int(rand() % 10 + 1);
(*ppMem)[i].segMesh.nbrTriangles = int(rand() % 10 + 1);
(*ppMem)[i].segMesh.vertices = (float *)malloc(sizeof(float) * (*ppMem)[i].segMesh.nbrVertices);
(*ppMem)[i].segMesh.triangles = (int *)malloc(sizeof(int) * (*ppMem)[i].segMesh.nbrTriangles);
for (int j = 0; j < (*ppMem)[i].segMesh.nbrVertices; j++)
{
(*ppMem)[i].segMesh.vertices[j] = float(j + 1);
}
for (int j = 0; j < (*ppMem)[i].segMesh.nbrTriangles; j++)
{
(*ppMem)[i].segMesh.triangles[j] = int(j + 1);
}
}
}}
Python代码:
from ctypes import *
import numpy as np
from numpy.ctypeslib import ndpointer
ndDLL = cdll.LoadLibrary("./MyDll.dll")
# Triangle Mesh Structure
class TriangleMesh(Structure):
_fields_ = [
("nbrVertices", c_int),
("nbrTriangles", c_int),
("vertices", POINTER(c_float)),
("triangles",POINTER(c_int))]
# LCSNoduleEx Structure
class ROI(Structure):
_fields_ = [
("xmm", c_double),
("ymm", c_double),
("zmm", c_double),
("diameter", c_double),
("level", c_double),
("volume", c_double),
("threshold", c_double),
("isMesh", c_int),
("mVol", c_double),
("mass", c_double),
("meanD", c_double),
("dve", c_double),
("dla", c_double),
("dsa", c_double),
("dla3D", c_double),
("spike", c_double),
("sphere", c_float),
("lais", c_float*6),
("said", c_float*6),
("la3D", c_float*6),
("mesh", TriangleMesh)
]
def PrintROI(pMem, NumROI):
for i in range():):
print("ROI %d"%(i), flush=True)
print("\tlevel %f"%(pMem[i].level), flush=True)
print("\tdiameter %f"%(pMem[i].diameter), flush=True)
print("\tdla3D %f"%(pMem[i].dla3D), flush=True)
print("\tddla %f"%(pMem[i].dla), flush=True)
print("\tmeanD %f"%(pMem[i].meanD), flush=True)
print("\tdai %f"%(pMem[i].dai), flush=True)
print("\tdve %f"%(pMem[i].dve), flush=True)
print("\tmass %f"%(pMem[i].mass), flush=True)
print("\tthreshold %f"%(pMem[i].threshold), flush=True)
print("\tspiculation %f"%(pMem[i].spike), flush=True)
print("\tspiculation2 %f"%(pMem[i].sphere), flush=True)
print("\tvolume %f"%(pMem[i].volume), flush=True)
print("\tmVol %f"%(pMem[i].mVol), flush=True)
print("\txmm %f"%(pMem[i].xmm), flush=True)
print("\tymm %f"%(pMem[i].ymm), flush=True)
print("\tzmm %f"%(pMem[i].zmm), flush=True)
print("\tla3D %f, %f, %f, %f, %f, %f"%(pMem[i].la3D[0],
pMem[i].la3D[1],
pMem[i].la3D[2],
pMem[i].la3D[3],
pMem[i].la3D[4],
pMem[i].la3D[5]), flush=True)
print("\tsais %f, %f, %f, %f, %f, %f"%(pMem[i].sais[0],
pMem[i].sais[1],
pMem[i].sais[2],
pMem[i].sais[3],
pMem[i].sais[4],
pMem[i].sais[5]), flush=True)
print("\tLAIS %f, %f, %f, %f, %f, %f"%(pMem[i].lais[0],
pMem[i].lais[1],
pMem[i].lais[2],
pMem[i].lais[3],
pMem[i].lais[4],
pMem[i].lais[5]), flush=True)
print("\tisMesh %d"%(pMem[i].isMesh), flush=True)
print("\tnbrVertices %d"%(pMem[i].mesh.nbrVertices))
print("\tnbrTriangles %d"%(pMem[i].mesh.nbrTriangles))
for j in range(pMem[i].mesh.nbrVertices):
print("\t\tVertices %d) %f"%(j,pMem[i].mesh.vertices[j]), flush=True)
for j in range(pMem[i].mesh.nbrTriangles):
print("\t\tTriangle %d) %d"%(j,pMem[i].mesh.triangles[j]), flush=True)
ndDLL.CreateROI.argtypes = [POINTER(POINTER(ROI)), POINTER(c_int)]
pMem= POINTER(LCSNoduleEx)()
NumROI = c_int(1)
ndDLL.CreateROI(byref(pMem),byref(NumROI) )
PrintROI(pMem, NumROI.value)发布于 2018-08-23 07:12:12
您的两个结构至少有两个不匹配。
我不知道哪一个是相关的,因为您的垃圾似乎在一个名为spic的字段中,该字段既没有出现在C++结构中,也没有出现在…的ctype中
首先,你会得到两个乱序的字段:
double threshold;
int isMesh;
double mVol;与
("threshold", c_double),
("mVol", c_double),
("isMesh", c_int),这看起来似乎没什么大不了的,但是一旦您将对齐驱动的填充放入混合中,可以想象这可能会导致所有后续字段都减少了4个字节。
然后,您对所有这些数组使用了错误的类型:
float lais[6];
float sais[6];
float la3D[6]; 与
("lais", c_double*6),
("said", c_double*6),
("la3D", c_double*6), float是32位;c_double是64位。lais[0]是由lais[0]和lais[1]打包在一起作为double的垃圾double,lais[4]是sais[2]和sais[3]打包在一起,la3D[4]是超出结构末尾的堆中的64个随机位。如果幸运的话,当你尝试读取它时,你会得到一个段错误,但是如果你不幸运,你就会得到很难调试的垃圾。
对于像这样真正复杂的结构,我通常不相信自己会手动编写ctypes版本,除非犯的错误至少是您的三倍。相反,我编写了一个快速脚本来解析头部(偶尔也会解析文档)并生成Python代码。对于像CoreFoundation和Win32头这样的东西,它们有数以千计的大得离谱的结构,它们都是以非常严格和可靠的风格编写的,我有反复使用的脚本。
https://stackoverflow.com/questions/51976302
复制相似问题