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

Decode C const char* in Python with 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

来自runSmpModel函数的const char*return值来自

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

在运行模型中,它的最终定义如下所示,其中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 如何使用 ctypes.

读取长度超过 15 个字符的 C char*

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

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