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

Decode C const char* in Python with ctypes

本文关键字:const char 解码 ctypes Python 使用      更新时间:2023-10-16

我在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变量并获取 CrunSmpModel函数传递的字符串。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*返回值来自

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 如何使用ctypes读取长度超过 15 个字符的 Cchar*

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

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