最近研究人脸识别,需要用python调用so动态库,涉及到c/c++中的指针字符串转Python的bytes对象的问题。
按照ctypes的文档,直观方式是先创建对应的类型数组,再将指针取地址一一赋值:

from ctypes import *
  
p=(c_char * )()
for i in range():
p[i] = i
 
b=bytes(bytearray(p))
print(b)

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=-):
"""string_at(addr[, size]) -> string
 
Return the string at addr."""
return _string_at(ptr, size)

_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 * )()
for i in range():
p[i] = i
 
m=cast(p, c_char_p)
print(m)

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)

from ctypes import * b=b'0123456789' m=cast(p, c_char_p) print(m)

吼吼,奇迹出现了,bytes对象cast成了char*指针。。。用string_at转换看看

string_at(m)

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 == -)
return PyString_FromString(ptr);
return PyString_FromStringAndSize(ptr, size);
}

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 ( == 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 == -)
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;
}

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; }

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

  1. 初始化char指针--赋值和strcpy() 本质区别【转】

    原文地址:http://hi.baidu.com/todaygoodhj/item/0500b341bf2832e3bdf45180 使用常量字符串初始化char指针,或者使用strcpy复制,从语法 ...

  2. char[]数组与char *指针的区别

    char[]数组与char *指针的区别 问题描述 虽然很久之前有看过关于char指针和char数组的区别,但是当时没有系统的整理,到现在频繁遇到,在string,char[], char *中迷失了 ...

  3. char指针

    1.在C语言中,没有字符串类型,因此使用char指针表示字符串. 2.那么问题来了,使用char* 表示字符串,到哪里是结尾呢?因此需要一个特殊的字符作为哨兵,类似迭代器中的end(),这个哨兵就是' ...

  4. char数组与char指针

    1.以字符串形式出现的,编译器会在结尾自动添加\0,思考,为什么? 存在的C语言方法,如strlen(s),计算字符串的长度,其中s指针.strlen要计算字符串长度,必须知道哪里是结尾,因此使用\0 ...

  5. C: 当字符数组首指针转化成char *指针,sizeof(*ptr)不为array的size

    #include <stdio.h> #include <string.h> int main() { char a[10] = "\0"; char *p ...

  6. char 指针如何判断字符串需要输出长度

    先上代码: #include <stdio.h> #include <string.h> ] = "; int func1(const char *ip) { pri ...

  7. C++中将对象this转换成unsigned char指针

    示例程序 // ---CodeBlob.h--- #ifndef CODEBLOB_H_ #define CODEBLOB_H_ class CodeBlob { private: const cha ...

  8. Java之byte、char和String类型相互转换

    package basictype; /** * byte.char和String类型相互转换 */ public class CHJavaType { public static void main ...

  9. python pip 'nonetype' object has no attribute 'bytes'

    python pip 'nonetype' object has no attribute 'bytes' 更新 pip for Windows : python -m pip install -U ...

随机推荐

  1. linux下的变量规则

    1.变量名可以由字母.数字和下划线组成,但是不能以数字开头: 2.变量在命名时,默认情况下为字符型: 3.为变量赋值时,等号两边不能有空格: 4.如果要增加变量的值,可以进行变量的叠加,不过需要将变量 ...

  2. SCUT - 483 - 数轴上的点

    https://scut.online/p/483 改了题目之后发现,其实n个点放在[1,2N],要求间距至少是2,那么有且只有一个点和前面点的间距是3(设-1存在一个点),其他点的间距都必须是2.排 ...

  3. stdcall 函数调用过程(以delphi为例),还有负数的补码

    以delphi下调用stdcall 函数为例,从右往左压栈:procedure TForm1.Button2Click(Sender: TObject);var i:integer;begin i:= ...

  4. html5酷炫效果链接收集

    HTML5 3D图片相册图片轮播动画   http://www.html5tricks.com/demo/html5-3d-gallery-animation/index.html 36种漂亮的CSS ...

  5. 一张图说明移动前端开发与web前端开发的区别

  6. js日期格式验证

    js日期格式验证 <input type="text" maxLength='10' onkeyup='checkDate(this.value,jQuery(this)); ...

  7. mysql复习(1)基本CRUD操作

    一.这段时间在学校,把之前的东西都好好捡起来. 0.下面介绍Mysql的最基本的增删改查操作,很多IT工作者都必须掌握的命令,也是IT面试最常考的知识点.在进行增删改查之前,先建立一个包含数据表use ...

  8. 1.利用canvas画一个太极图

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. express与koa对比

    使用体验koaconst Koa = require('koa');const app = new Koa();app.use(ctx => { ctx.body = 'Hello Koa'; ...

  10. java 技术分享

    http://www.ccblog.cn/99.htm http://www.ccblog.cn/100.htm http://www.ccblog.cn/101.htm http://www.ccb ...