V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
explist
V2EX  ›  Python

PY 的 C 扩展疑问

  •  
  •   explist · 2017-02-25 17:32:42 +08:00 · 1928 次点击
    这是一个创建于 2617 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有如下一个用 C 写的扩展模块: mytest. 我的问题是:在 PY 中如何给实参呢?

    #include <stdio.h>

    #include "Python.h"

    char* gets_s(char s[],int n) {

    int c;
    char *cs;
    if((cs=s)==NULL) return NULL;    
    while(--n>0 && (c=getc(stdin))!=EOF && c!='\n')
        *cs++=c;
    *cs='\0';
    return (c==EOF && cs==s) ||(c=='\n' && cs==s)? NULL : s ;
    

    }

    static PyObject* mytest_get(PyObject *self, PyObject *args) {

    int n;
    char * s=NULL;
    if(!PyArg_ParseTuple(args, "si", &s, &n))
            return NULL;
    return (PyObject*)Py_BuildValue("s", gets_s(s,n));
    

    }

    #python 中:

    import mytest

    from ctypes import *

    arr = (c_byte * 10)() # c_char*10

    print('input: ')

    mytest.gets_s(arr,10)# TypeError: must be str, not c_byte_Array_10

    //另外在C中如何写这样的导出函数:

    struct demo {

        char name[10];
        int age;
    };
    

    void GetString(struct demo *p) {

        strcpy(p->name, "My Test");
        p->age = 1;
    }
    

    static PyObject* wrap_GetString(PyObject *self, PyObject *args) {

    struct demo* s;
    

    if(!PyArg_ParseTuple(args, "?", &s)) //这里的类型如何写?

    3 条回复    2017-03-01 18:11:46 +08:00
    wangxn
        1
    wangxn  
       2017-02-26 01:37:22 +08:00 via Android
    这么复杂的东西怎么能三言两语说清楚,楼主去啃啃文档中扩展开发相关的内容吧。
    MetaGen
        2
    MetaGen  
       2017-02-26 20:23:41 +08:00
    用 cffi 多简单,为啥要用 CPython 的接口
    Daetalus
        3
    Daetalus  
       2017-03-01 18:11:46 +08:00   ❤️ 1
    第一个问题,从原理上来说, Python 中字符串是不可变的。而根据 C 模块的代码,"si"表示接收的是字符串,而 Python 中字符串是不可变的,因此不能像 C 语言中那样先创建一个长度为 10 的空字符串,然后传入函数,在函数中修改其中的内容(这只是原理,你的代码中并没有修改)。因此要么用字符列表,要么就改变思维方式。

    又看了下你的代码,我觉得可以直接使用 input()函数,获取字符串对象,然后传到 C 层面中并解析给一个 const char*对象。如果仅仅想实验一些 C API 的功能,还是要注意 Python 和 C 在思维上的差别。

    PS :你的 C 代码写的不错啊!看上去是有经验的。


    第二个问题, Python 中所有都是对象,这个对象在 C 层面指的是 PyObject ,所以从 Python 层面传来的参数不能直接通过`if(!PyArg_ParseTuple(args, "?", &s))`解析给 C 层面的纯 struct 对象。

    有几种解决方案:

    1 、弄个中间的结构体,其中含有 PyObject_HEAD :

    typedef struct {
    PyObject_HEAD
    xxx;
    } PyXxxxObject;

    然后将这个对象转成 demo 对象。要么直接把 demo 定义成 PyObject 对象。之后就是传递 O 对象了。

    2 、使用 struct 模块,位于标准库中,不用担心移植性。具体参考相关文档。

    3 、利用 PyDictObject 和 PyListObject 进行一些较为复杂的模拟。应该是可行的,但我没想好细节。就不给出代码了。

    对了,强烈、强烈建议不要混用 ctype 和 Python C API 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1129 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 18:41 · PVG 02:41 · LAX 11:41 · JFK 14:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.