[轉] 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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM