我有一个C ++函数的extern "C"
声明,编译为Ubuntu上的共享库的一部分,getVPHistory
void getVPHistory(actorPos allPostions[], uint numAct, uint numDim, uint numState) {
uint actorDimPairCount = numAct * numDim;
uint actorDimPairIndex = 0;
float val = 1.0;
for (uint actor = 0; actor < numAct; ++actor) {
for (uint dim = 0; dim < numDim; ++dim) {
actorPos *ap = &allPostions[actorDimPairIndex];
++actorDimPairIndex;
ap->actor = actor;
ap->dim = dim;
ap->nState = numState;
for (uint state = 0; state < numState; ++state) {
ap->pos[state] = val;
val += 0.5; // incrementing is just for testing
}
}
}
}
actorPos
对象定义为:
using actorPos = struct singleActorPositions {
unsigned int actor;
unsigned int dim;
unsigned int nState;
float pos[1000]; // possible upper limit of nState
};
我在python中使用ctypes
尝试使用此函数,使用以下代码:
import ctypes as c
actorCnt = 2 dimensionCnt = 2; stateCnt = 2
smpLib = c.cdll.LoadLibrary('libsmpDyn.so')
class PosHist(c.Structure):
_fields_ = [("actorID",c.c_uint),\
("dimensionID",c.c_uint),\
("stateCnt",c.c_uint),\
('positions',c.c_float*stateCnt)]
posHistArrType = PosHist*(actorCnt*dimensionCnt)
posHists = posHistArrType()
proto_PS = c.CFUNCTYPE(c.c_voidp,c.POINTER(posHistArrType),c.c_uint,c.c_uint,c.c_uint)
getVPHistory = proto_PS(('getVPHistory',smpLib))
getVPHistory(posHists,actorCnt,dimensionCnt,stateCnt)
这样运行没有错误,但是当我尝试访问posHists
内的返回数据时,我看到只有第一个对象被填充。运行这个:
for p in posHists:
print('Actor: %d, Dimension: %d'%(p.actorID,p.dimensionID))
for o in p.positions:
print('\t%0.2f'%o)
给我这个:
Actor: 0, Dimension: 0
1.00
1.50
Actor: 0, Dimension: 0
0.00
0.00
Actor: 0, Dimension: 0
0.00
0.00
Actor: 0, Dimension: 0
0.00
0.00
即,在数组中的第一个PosHist
对象之后,所有其他对象仍然只显示初始值。我可以确认getVPHistory
函数完全填满了数组,所以在我看来,完整数组的问题没有传回我的posHists
变量。求救!
怀疑结构是问题的一部分 - 并且最终还不仅仅是问题所需要的 - 我已将其简化为仅使用三维数组。 C getVPHistory
函数现在是:
void getVPHistory(float hist[100][100][100], uint numAct, uint numDim, uint numState)
{
// talk a little
cout << "Actors: " << numAct << "Dimensions: " << numDim << "States: " << numState << endl;
// loop through all actors, dims, and states and store the positions
float val = 1.0;
for (uint actor = 0; actor < numAct; ++actor)
{
//cout << "Actor " << actor << endl;
for (uint dim = 0; dim < numDim; ++dim)
{
//cout << "Dimension " << dim << endl;
for (uint state = 0; state < numState; ++state)
{
hist[actor][dim][state] = val;
cout << "A: " << actor << " D: " << dim << " S: " << state << "\tAdded position: " << val << endl;
val += 0.5;
}
}
}
}
现在是python代码:
actorCnt = 3; dimensionCnt = 2; stateCnt = 5
posHistType = ((c.c_float * stateCnt) * dimensionCnt)*actorCnt
proto_PS = c.CFUNCTYPE(c.c_voidp,c.POINTER(posHistType),c.c_uint,c.c_uint,c.c_uint)
getVPHistory = proto_PS(('getVPHistory',smpLib))
posHists = posHistType()
getVPHistory(posHists,actorCnt,dimensionCnt,stateCnt)
for a in range(actorCnt):
for d in range(dimensionCnt):
print('Pos Hist for Actor %d, Dimension %d:'%(a,d))
print('\t[%s]'%', '.join(['%0.2f'%p for p in posHists[a][d]]))
所以现在我传递一个指向内存的指针,用于三维数组,数据用C填充,然后我在python中读取数据。来自C的控制台输出验证数据是否正在存储:
Actors: 3 Dimensions: 2 States: 5
A: 0 D: 0 S: 0 Added position: 1
A: 0 D: 0 S: 1 Added position: 1.5
A: 0 D: 0 S: 2 Added position: 2
A: 0 D: 0 S: 3 Added position: 2.5
...
A: 2 D: 1 S: 2 Added position: 14.5
A: 2 D: 1 S: 3 Added position: 15
A: 2 D: 1 S: 4 Added position: 15.5
然而,即使没有结构的复杂性,我也有同样的问题,只有第一个最内层的数据返回数据:
Pos Hist for Actor 0, Dimension 0:
[1.00, 1.50, 2.00, 2.50, 3.00]
Pos Hist for Actor 0, Dimension 1:
[0.00, 0.00, 0.00, 0.00, 0.00]
Pos Hist for Actor 1, Dimension 0:
[0.00, 0.00, 0.00, 0.00, 0.00]
Pos Hist for Actor 1, Dimension 1:
[0.00, 0.00, 0.00, 0.00, 0.00]
Pos Hist for Actor 2, Dimension 0:
[0.00, 0.00, 0.00, 0.00, 0.00]
Pos Hist for Actor 2, Dimension 1:
[0.00, 0.00, 0.00, 0.00, 0.00]
如果我将C函数定义中的数组硬编码为hist[3][2][5]
- 与在python中创建的相同 - 会发生相同的行为。
答案 0 :(得分:0)
您必须在C ++和Python之间声明具有相同维度的结构:
工作(Windows)C ++ DLL:
typedef unsigned int uint;
struct actorPos
{
unsigned int actor;
unsigned int dim;
unsigned int nState;
float pos[1000]; // possible upper limit of nState
};
extern "C" __declspec(dllexport)
void getVPHistory(actorPos allPostions[], uint numAct, uint numDim, uint numState)
{
uint actorDimPairIndex = 0;
float val = 1.0;
for(uint actor = 0; actor < numAct; ++actor)
{
for(uint dim = 0; dim < numDim; ++dim)
{
actorPos* ap = &allPostions[actorDimPairIndex];
++actorDimPairIndex;
ap->actor = actor;
ap->dim = dim;
ap->nState = numState;
for(uint state = 0; state < numState; ++state)
{
ap->pos[state] = val;
val += 0.5; // incrementing is just for testing
}
}
}
}
Python代码:
import ctypes as c
actorCnt = 2; dimensionCnt = 2; stateCnt = 2
smpLib = c.CDLL('test')
class PosHist(c.Structure):
_fields_ = [("actorID",c.c_uint),\
("dimensionID",c.c_uint),\
("stateCnt",c.c_uint),\
('positions',c.c_float*1000)] # declare same size as struct in C++
posHistArrType = PosHist*(actorCnt*dimensionCnt)
posHists = posHistArrType()
proto_PS = c.CFUNCTYPE(c.c_voidp,c.POINTER(posHistArrType),c.c_uint,c.c_uint,c.c_uint)
getVPHistory = proto_PS(('getVPHistory',smpLib))
getVPHistory(posHists,actorCnt,dimensionCnt,stateCnt)
for p in posHists:
print('Actor: %d, Dimension: %d'%(p.actorID,p.dimensionID))
# Here, iterate only the number of states returned...
for i in range(p.stateCnt):
print('\t%0.2f'%p.positions[i])
输出:
Actor: 0, Dimension: 0
1.00
1.50
Actor: 0, Dimension: 1
2.00
2.50
Actor: 1, Dimension: 0
3.00
3.50
Actor: 1, Dimension: 1
4.00
4.50