猿问

如何从内存分配发生在C层的Python脚本将float*数组传递给C方法

我试图从Python脚本调用C方法,C方法调用反过来C++方法。我使用 malloc() 在 getResults() 方法内分配数组。现在的问题是如何将参数传递给 python 脚本中的 float* oresults,其内存分配发生在 C 层内。这是io.c


int getResults(char* iFilename, char* iStagename, int iStateidCnt, 

    int* Stateids, int iEntityIdCount, int* iEntityids, char* iEntityType,

    char* iVariablegroup, char* ivariable, int *oRescount,

    float* oResults)

{

    int Status, i;

        EString etype(iEntityType), stagename(iStagename);

    EString vargroup(iVariablegroup);

    std::vector<ERF_INT> entity_ids;

    std::vector<ERF_INT> stateids;

    std::vector<ERF_FLOAT> results;

    _CopyIntArrayIntoVector(iStateidCnt, Stateids, stateids);

    _CopyIntArrayIntoVector(iEntityIdCount, iEntityids, entity_ids);

    CreateIoInstance(iFilename, iStagename);

    ioData pIodata = CreateIoDataInstance();

    if (iEntityIdCount <= 0)

        pIodata.setWholeSection(true);

    else

    {

        pIodata.setWholeSection(false);

        pIodata.setEntityList(entity_ids);

    }

        

    pIodata.setStateList(stateids);

    pIodata.setType(etype);

    pIodata.setVariableGroup(iVariablegroup);

    pIodata.setVariable(ivariable);

        //This is C++ method

    Status = pIo->get_results(pIodata, results);

    *oRescount = results.size();

        //allocation for oresults whose size > 2

    oResults = (float*)malloc(results.size() * sizeof(float));

    _CopyVectorIntoDoubleArray(results, oResults);

    return Status;

}

TypeError: byref() 参数必须是 ctypes 实例,而不是 '_ctypes.PyCPointerType' 这是我运行脚本时收到的错误。我对如何在脚本中发送 float *oresults 的参数有点困惑。



喵喔喔
浏览 126回答 2
2回答

繁星点点滴滴

在 C++ 代码中,签名int getResults(..., float* oResults)无法将分配的指针传回调用者。线路oResults = (float*)malloc(results.size() * sizeof(float));在 getResults 中本地设置oResults指针,而不影响调用者。为了输出指针,您必须使用return它或使用指针到指针参数:int getResults(..., float** oResults)。在Python代码中,我不熟悉ctypes,但它看起来float_values = POINTER(c_float)是一个问题。为浮点指针POINTER(c_float)创建 Python类型。您想要POINTER(c_float)()创建这样一个指针的实例(最初为空)。

慕婉清6462132

该float* oResults参数是按值传递的,因此不可能返回该参数中已分配的指针。相反,使用float** oResults.另外,float_values = POINTER(c_float)是类型,而不是类型的实例。所以byref(float_values)相当于无效的 C &(float*)。相反,您需要一个指针的实例POINTER(c_float)()(注意括号)并通过引用传递它,类似于 C float *p; func(&p)。这会将指针按地址传递给 C 函数,然后函数可以将其修改为输出参数。这是一个简化的示例,仅关注int *oRescount和float** oResults参数。还需要一个释放分配的函数:测试.cpp#include <vector>#define API __declspec(dllexport)extern "C" {&nbsp; &nbsp; API int getResults(size_t *oRescount, float** oResults) {&nbsp; &nbsp; &nbsp; &nbsp; std::vector<float> results {1.25,2.5,3.75,5.0}; // Simulated results&nbsp; &nbsp; &nbsp; &nbsp; *oRescount = results.size(); // Return size of results&nbsp; &nbsp; &nbsp; &nbsp; auto tmp = new float[results.size()]; // allocate&nbsp; &nbsp; &nbsp; &nbsp; for(size_t i = 0; i < results.size(); ++i) // copy vector to allocation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tmp[i] = results[i];&nbsp; &nbsp; &nbsp; &nbsp; *oResults = tmp; // return allocation&nbsp; &nbsp; &nbsp; &nbsp; return 0;&nbsp; &nbsp; }&nbsp; &nbsp; API void freeResults(float* oResults) {&nbsp; &nbsp; &nbsp; &nbsp; delete [] oResults;&nbsp; &nbsp; }}test.pyfrom ctypes import *dll = CDLL('./test')dll.getResults.argtypes = POINTER(c_size_t),POINTER(POINTER(c_float))dll.getResults.restype = c_intdef getresults():&nbsp; &nbsp; oRescount = c_size_t()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# instance to hold the returned size&nbsp; &nbsp; oResults = POINTER(c_float)()&nbsp; # instance of a float* to hold the returned allocation.&nbsp; &nbsp; err = dll.getResults(byref(oRescount), byref(oResults))&nbsp; &nbsp; # oResults is a float* and it is possible to index past the end.&nbsp; &nbsp; # Make a copy into a Python list slicing to the correct size,&nbsp; &nbsp; # then free it so there is no memory leak.&nbsp; &nbsp; results = oResults[:oRescount.value]&nbsp; &nbsp; dll.freeResults(oResults)&nbsp; &nbsp; return err,resultserr,ores = getresults()print(err,ores)输出:0 [1.25, 2.5, 3.75, 5.0]
随时随地看视频慕课网APP

相关分类

Python
我要回答