• [转] python关于ctypes使用char指针与bytes相互转换的问题


    最近研究人脸识别,需要用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转换看看

    string_at(m)

    总结一下:
    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;
    }
  • 相关阅读:
    php
    图片拖拽
    12.20
    正则详细讲解
    12.19
    正则
    闭包
    date类
    二分查找
    冒泡排序
  • 原文地址:https://www.cnblogs.com/hjbf/p/11969521.html
Copyright © 2020-2023  润新知