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
GYGYG
V2EX  ›  Python

求助。 Python 使用 ctypes 库调用 C 语言 so 动态库遇到困难。

  •  1
     
  •   GYGYG · 2020-06-29 11:29:13 +08:00 · 1648 次点击
    这是一个创建于 1641 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近接到一个需求,要用 python 封装一个 c 语言的 so 。好久没动过 C 语言了。

    目前 c 程序调用调通了,代码如下:

    #include <stdio.h>
    #include "fm_def.h"
    #include "fm_cpc_pub.h"
    
    
    static unsigned char dev_index = 0;
    static unsigned int dev_type = 0xE600;
    static unsigned int dev_flag = 0x00000002;
    static void * dev;
    
    
    int main()
    {
        unsigned int code = FM_CPC_OpenDevice(&dev_index,dev_type,dev_flag,&dev);
        printf("%d\n",code);
    }
    

    python 封装这边,用了 ctypes 库调用 so,代码如下:

    #!/usr/bin/env python3
    from ctypes import *
    
    cur = cdll.LoadLibrary('./libfmapiv100.so')
    
    dev_index = c_ubyte(0)
    dev_type = c_uint(0xE600)
    dev_flag = c_uint(0x00000002)
    dev = c_void_p()
    
    code = cur.FM_CPC_GetDeviceInfo(byref(dev_index), 7, 1, byref(dev))
    print(code)
    

    这段代码报错 Segmentation fault,查了下大概率是参数格式问题。 如果参数列表写成

    code = cur.FM_CPC_GetDeviceInfo(dev_index, 7, 1, byref(dev))
    

    会返回 errorcode ( so 的错误代码),个人感觉是我第一个参数格式写的有问题。

    求救啊!或者有什么别的方案也指导下!多谢!!

    第 1 条附言  ·  2020-06-29 15:57:14 +08:00

    这边贴下最新的python代码:

    #!/usr/bin/env python3
    from ctypes import *
    
    
    dev_index = c_ubyte(0)
    dev_type = c_uint(0xE600)
    dev_flag = c_uint(0x00000002)
    dev = c_void_p()
    
    cur = cdll.LoadLibrary('./libfmapiv100.so')
    cur_get_device = cur.FM_CPC_GetDeviceInfo
    cur_get_device.argtypes = (c_ubyte, c_uint, c_uint, c_void_p)
    cur_get_device.restype = c_uint
    code = cur_get_device(dev_index, dev_type, dev_flag, byref(dev))
    print(code)
    

    结果为:code = 421060613 调用C库中另外一个翻译errorcode的接口结果如下:

    FileName:api_main.c, Line:796  error parameter
    

    所以还是(dev_index, dev_type, dev_flag, byref(dev))这里出了问题嘛,难道是空指针void *不能这样传入?这个空指针也是这个函数的出参。

    4 条回复    2020-06-29 18:33:01 +08:00
    Pagliacii
        1
    Pagliacii  
       2020-06-29 11:37:30 +08:00
    不应该是

    ```
    code = cur.FM_CPC_GetDeviceInfo(byref(dev_index), c_uint(7), c_uint(1), byref(dev))
    ```

    ?

    通过调用 ctypes 的 c_uint 把 Python 中的数据对象转换成 C 中能识别的数据类型
    Pagliacii
        2
    Pagliacii  
       2020-06-29 11:40:27 +08:00
    还有另一种写法就是声明 FM_CPC_GetDeviceInfo 的 argtypes 和 restype 。https://gist.github.com/Pagliacii/774ed5d3ea78a36cdb0754be6a25408d
    GYGYG
        3
    GYGYG  
    OP
       2020-06-29 12:00:38 +08:00
    @Pagliacii 啊才发现我写错了,这个 7,1 位置是 dev_type,dev_flag 。
    我试试这个 argtypes 好了。
    感谢。
    GYGYG
        4
    GYGYG  
    OP
       2020-06-29 18:33:01 +08:00
    解决了朋友们,我写错了接口名,导致的一直报错。现在的感受简直想挖个地洞钻进去,浪费了半天时间,系统复习了 C 的指针,算不亏把。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5668 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 03:13 · PVG 11:13 · LAX 19:13 · JFK 22:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.