使用ctypes在Python中解码C const char *

时间:2017-08-12 19:34:40

标签: python c++ c ctypes

我在Python 3中使用ctypes(导入为c)来执行C ++共享库。使用以下代码将库加载到python中:

smpLib = c.cdll.LoadLibrary(os.getcwd()+os.sep+'libsmpDyn.so')

其中一个函数具有extern 'C'声明const char* runSmpModel(...)。 python函数原型编码并运行为:

proto_SMP = c.CFUNCTYPE(c.c_char_p,...)
runSmpModel = proto_SMP(('runSmpModel',smpLib))
res = runSmpModel(...)

这一切都很好用,但我无法解码res变量并获取C runSmpModel函数传递的字符串。显示res的值(我使用ipython3)为b'\xd0'。我在网上找到的最佳解决方案 - res.decode('utf-8')给了我错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd0 in position 0: unexpected end of data

const char*函数的runSmpModel返回值来自

std::string scenID = SMPLib::SMPModel::runModel(...);
return scenID.c_str();

在runModel中,最终定义如下所示,其中scenName是输入字符串:

auto utcBuffId = newChars(500);
sprintf(utcBuffId, "%s_%u", scenName.c_str(), microSeconds); // catenate scenario name & time
uint64_t scenIdhash = (std::hash < std::string>() (utcBuffId)); // hash it

auto hshCode = newChars(100);
sprintf(hshCode, "%032llX", scenIdhash);
scenId = hshCode;

此特定res的值应为0000000000000000BBB00C6CA8B8872E。我该如何解码这个字符串?

经过大量的进一步测试后,我将问题确定为从C函数传递的字符串的长度。没有问题,如果字符串的长度最多为15个字符,但如果它是16或更长 - 没有骰子。对于最小化工作示例,C代码为:

extern "C" {
  const char* testMeSO()
  {
    string scenarioID = "abcdefghijklmnop";
    return scenarioID.c_str();
  }
}

和python代码(与上面显示的smpLib相同):

proto_TST = c.CFUNCTYPE(c.c_char_p)
testMeSO = proto_TST(('testMeSO',smpLib))
res = testMeSO()
print("Scenario ID: %s"%res.decode('utf-8'))

这会产生解码错误,除非从C函数中的scenarioID变量中删除任何字符。因此,似乎问题是“Python如何使用char*读取长度超过15个字符的C ctypes

1 个答案:

答案 0 :(得分:0)

经过几天的调试和测试,我终于使用了@Petesh on this SO post发布的第二个解决方案。我不明白为什么ctypes明显限制从C传递的char *值到15个字符(+终止= 256位?)。

基本上,解决方案是将已使用char * buff创建的额外ctypes.create_string_buffer(32*16)缓冲区以及值为32 * 16的unsigned int buffsize传递给C函数。然后,在C函数中执行scenarioID.copy(buff,buffsize)。 python原型函数以明显的方式进行了修改。