【发布时间】:2017-08-20 12:36:24
【问题描述】:
我有一个 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 变量的问题。请帮忙!
编辑
怀疑结构是问题的一部分——最终超出了问题的需要——我已将其简化为仅使用 3-d 数组。 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]]))
所以现在我将一个指向内存的指针传递给一个 3-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 中创建的相同 - 会发生相同的行为。
【问题讨论】:
-
这个
stateCnt = 2 ... ('positions',c.c_float*stateCnt)似乎与float pos[1000]有些不匹配 -
如果你指定一个数组长度within一个结构,你必须始终使用相同的长度。您将它们放在一个 array 中。或者,使用 pointer-to-structure 代替。
-
谢谢,但
pos[1000]不是问题,因为getVPHistory()函数在从 C 中以相同方式调用时可以正常工作。无论如何,我看不到如何分配足够的内存对于 1000 个条目,则仅填充 2 的数据会导致传回的内存仅显示 1 中的数据! -
假设使用的 C 编译器支持 VLA(C++ 编译器不会,顺便说一句)试试这个:
void getVPHistory(uint numAct, uint numDim, uint numState, float hist[numAct][numDim][numSate]);(这里的顺序很重要) -
试过@alk,没有运气(使用 gcc)。