最近研究人脸识别,需要用python调用so动态库,涉及到c/c++中的指针字符串转Python的bytes对象的问题。
按照ctypes的文档,直观方式是先创建对应的类型数组,再将指针取地址一一赋值:
from ctypes import *
p=(c_char * 10)()
for i in range(10):
p[i] = i
b=bytes(bytearray(p))
print(b)
|
搜寻了各种资料,都未能找到更好的。。。直到
ctypes.string_at
_string_at = PYFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
def string_at(ptr, size=-1):
"""string_at(addr[, size]) -> string
Return the string at addr."""
return _string_at(ptr, size)
|
于是char*转bytes可以直接用string_at方法,传入指针地址,以及字符串长度即可。
同样的问题,bytes对象需要传给c/c++代码。。。
直观方式同样是创建char数组array,拷贝bytes之后,再用cast强制转换成c_char_p
from ctypes import *
p=(c_char * 10)()
for i in range(10):
p[i] = i
m=cast(p, c_char_p)
print(m)
|
比较奇葩的是cast得到的对象,如果我们直接用bytes对象cast。。。
from ctypes import *
b=b'0123456789'
m=cast(p, c_char_p)
print(m)
|
吼吼,奇迹出现了,bytes对象cast成了char*指针。。。用string_at转换看看
总结一下:
1、bytes基于
Buffer Protocol
,查看其c实现
https://hg.python.org/cpython/file/3.4/Objects/bytesobject.c
2、string_as的c代码https://hg.python.org/cpython/file/3717b1481d1b/Modules/_ctypes/_ctypes.c
static PyObject *
string_at(const char *ptr, int size)
if (size == -1)
return PyString_FromString(ptr);
return PyString_FromStringAndSize(ptr, size);
3、cast的c代码同样在_ctypes.c(https://hg.python.org/cpython/file/3717b1481d1b/Modules/_ctypes/_ctypes.c)
static PyObject *
cast(void *ptr, PyObject *src, PyObject *ctype)
CDataObject *result;
if (0 == cast_check_pointertype(ctype))
return NULL;
result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
if (result == NULL)
return NULL;
The casted objects '_objects' member:
It must certainly contain the source objects one.
It must contain the source object itself.
if (CDataObject_Check(src)) {
CDataObject *obj = (CDataObject *)src;
/* CData_GetContainer will initialize src.b_objects, we need
this so it can be shared */
CData_GetContainer(obj);
/* But we need a dictionary! */
if (obj->b_objects == Py_None) {
Py_DECREF(Py_None);
obj->b_objects = PyDict_New();
if (obj->b_objects == NULL)
goto failed;
Py_XINCREF(obj->b_objects);
result->b_objects = obj->b_objects;
if (result->b_objects && PyDict_Check(result->b_objects)) {
PyObject *index;
int rc;
index = PyLong_FromVoidPtr((void *)src);
if (index == NULL)
goto failed;
rc = PyDict_SetItem(result->b_objects, index, src);
Py_DECREF(index);
if (rc == -1)
goto failed;
/* Should we assert that result is a pointer type? */
memcpy(result->b_ptr, &ptr, sizeof(void *));
return (PyObject *)result;
failed:
Py_DECREF(result);
return NULL;
原文链接:https://www.cnblogs.com/hjbf/p/11969521.html
在上面的代码中,POINTER(c_uint)()创建了一个类型为无符号整数(unsigned int)的指针,而string_at函数则将0x1000地址处的内容读取为字节数组,然后再将该数组传递给memmove函数以更新指针所指向的内存位置。使用Python ctypes.string_at函数,您可以轻松快速地读取和处理二进制数据,这对于需要快速高效地进行各种操作的应用程序非常有用。除了读取二进制数据之外,Python ctypes.string_at还可以读取其他类型的数据,例如字符串或结构体等。
public static byte[] charToByte(char c) {
byte[] b = new byte[2];
b[0] = (byte) ((c & 0xFF00) >> 8);
b[1] = (byte) (c & 0xFF);
python访问C/C++python的底层大部分都是C/C++实现,python和C和C++具有天然的互相调用优势;很多核心的算法库都是C/C++写的,在python开发过程中,经常访问别人的动态库;知名人工智能(深度学习)框架训练系统都是python写的,而运行时一般都是以动态库的形式提供;python访问C/C++的方式ctypes;pybind11;cffiswigctypes的优势不要修...
byref函数类似于C语言中的取地址符号&,其直接返回当前参数的地址,而pointer函数更为高级,其返回一个POINTER指针类型,一般来说,如果不需要对指针进行其他额外处理,推荐直接调用byref函数获取指针,这是较pointer更加快速的方法。POINTER指针类型在传参时也可直接作为指针传入C语言函数,但在Python中,其需要先访问 contents 属性,得到指针指向的数据,其一般为ctypes类型的实例,然后再访问 value 属性,得到实例所对应的Python类型的数据。
python的官方文档里面有很多关于ctypes的描述,下面我截取了一部分便于自己以后再次查看,欢迎有需要的朋友也可以看看。
class ctypes.c_byte
代表 C signed char 数据类型,并将值解读为一个小整数。 该构造器接受一个可选的整数初始化器;不会执行溢出检查。
class ctypes.c_char
代表 C char 数据类型,并将值解读为单个字符。 该构造器接受一个可选的字符串初始化器,字符串的长度必须恰好为一个字符。
class ctypes.c_char_p
当指向一个
~5个一行行代码,粘贴整个东西::#include #if defined(_WIN32)# define DLL_EXPORT __declspec(dllexport)#else# define DLL_EXPORT#endif#define LEN 5typedef struct CharPtrWrapperTag {int len;char *data;} CharPtrWrapper...
在做复杂计算时,Python的执行效率是无法同C比的。而且有些算法已经有开源的C库了,我们也没必要用Python重写一份。那Python怎么调用C语言写的程序库呢?答案就在Python提供的ctypes库,它提供同C语言兼容的数据类型,可以很方便地调用C语言动态链接库中的函数。使用C标准库函数我们来试试调用C标准库函数:from ctypes import cdlllibc = cdll.Load...
早餐店不会开到晚上,想吃的人早就来了!😄
在传递参数时,需要将python的类型转换成c语言支持的类型,接收返回值时,需要将c语言支持的类型转换成python的类型。
这里就需要知道2种类型之间对应的关系。
一、c语言转换到python字符串类型
1. 单个字符
b'\x5f'.hex() # 111 ns
'香香香'.encode() # 139 ns 仅字符串
binascii.b2a_hex(b'\xb9\x01\xef') # 172 ns 仅字符串
struct.pack('>i',65535) # 211 ns 仅符合C语言标准结构
int('101',8) # 224 ns
bytes.fromhex('ff ff ff') # 231 ns 仅hex字符
int.to_bytes(1111,
given a string:msg="hello world"How can I define this as a ctypes.c_void_p() data type?the following code yields a "cannot be converted to pointer" exception:data=ctypes.c_void_p(msg)data is required ...
我正在使用ctypes将一些C函数从DLL公开到Python脚本。其中一个函数返回一个动态大小的字符数组,我希望能够在Python中读取这个数组的内容,但是当我完成它时,属性句柄也会释放数组的内存。Python ctypes.string_at释放行为的C语言代码:...#ifdef __cplusplusextern "C"{#endif__declspec(dllexport) char * ...
|
|