最近研究人脸识别,需要用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. 最少多少人说谎(dp)

    https://ac.nowcoder.com/acm/contest/1168/H 题意:n个学生,邓志聪想知道这些学生的考试情况,于是一个一个叫这些学生叫去办公室问他们,但是有些学生并没有讲真话, ...

  2. DotNetCore知识栈

    #..NET Core提供的特性 1.开源.免费 2.轻量级.跨平台 3.组件化.模块化.IOC+Nuget.中间件 4.高性能 5.统一了MVC和WebAPI编程模型 a)  比如:ASP.NET ...

  3. 学习Golang语言(6):类型--切片

    学习Golang语言(1): Hello World 学习Golang语言(2): 变量 学习Golang语言(3):类型--布尔型和数值类型 学习Golang语言(4):类型--字符串 学习Gola ...

  4. 去掉img与img之间,video与video之间默认的间距(3种方式)

    img,video{ /*第1种方式*/ border:; vertical-align: bottom; /*第2种方式*/ outline-width:0px; vertical-align:to ...

  5. oracle在没

    db_user表中数据: name age nub 张三 13 13 张三 12 12 张三 12 13 张三 12 13 李四 12 12 李四 12 12 查询重复数据(一条) sql:selec ...

  6. Antd时间选择框汉化问题总结------国际化全局设置

    import zh_CN from 'antd/lib/locale-provider/zh_CN'; import 'moment/locale/zh-cn'; import { ConfigPro ...

  7. intellij idea 的快捷键方法

    1.Ctrl+N按名字搜索类 相当于eclipse的ctrl+shift+R,输入类名可以定位到这个类文件,就像idea在其它的搜索部分的表现一样,搜索类名也能对你所要搜索的内容多个部分进行匹配,而且 ...

  8. Spring基础07——配置集合属性

    1.集合属性 在Spring中可以通过一组内置的xml标签(例如<list>,<set>或<map>)来配置集合属性. 2.配置List集合 配置java.util ...

  9. rest_framework框架的版本

    REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer','rest_framewo ...

  10. Comet OJ - Contest #2 C题 言论的阴影里妄想初萌

    题目描述 Takuru 是一名能力者,他在地震时获得了念力致动的能力.所以他经常用自己的能力去干一些奇奇怪怪的事情. 有一天他获得了一张 nn 个点的无向完全图,之后他使用了能力,导致这张图的 \fr ...