返回与指针赋值之间的 c_char_p 行为不一致

Inconsistent c_char_p behavior between returning vs pointer assignment

考虑以下 C 函数:

void AssignPointer(char **p) {
    *p = "Test1";
}

char* Return() {
    return "Test2";
}

现在考虑 Python 中的以下代码:

import ctypes

lib = CDLL('LibraryPathHere')

lib.AssignPointer.restype = None
lib.AssignPointer.argtypes = (ctypes.POINTER(ctypes.c_char_p),)

lib.Return.restype = ctypes.c_char_p
lib.Return.argtypes = None

def to_python_string(c_str : ctypes.c_char_p) -> str:
    return c_str.value.decode('ascii')

现在以下工作:

c_str = ctypes.c_char_p()
lib.AssignPointer(ctypes.byref(c_str))
print(to_python_string(c_str))

但是下面给出 AttributeError: 'bytes' object has no attribute 'value' :

c_str = lib.Return()
print(to_python_string(c_str))

在第一种情况下,调试器将 c_str 显示为 c_char_p(ADDRESS_HERE)。在第二种情况下,调试器将 c_str 显示为 b'Test2'.

这是 Python/ctypes 中的错误还是我做错了什么?

ctypes automatically converts c_char_p return 值到字节对象。

Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.

如果您想要实际的指针值,请使用 ctypes.POINTER(ctypes.c_char) 作为 restype

最后,这里有一个解决此问题的方法:

为了避免 c_char_p 自动转换为 bytes,将 C 函数的 restype 设置为 c_void_p:

lib.Return.restype = ctypes.c_void_p

然后 castc_char_p,然后再传递给期望 c_char_p 作为常见情况的函数:

void_ptr = lib.Return()
c_str = ctypes.cast(void_ptr, ctypes.c_char_p)
print(to_python_string(c_str))