代码之家  ›  专栏  ›  技术社区  ›  Keeways

C到Python,通过Ctypes-包装指向静态函数的函数指针的结构

  •  2
  • Keeways  · 技术社区  · 6 年前

    我在C库中有这样的结构。 DataFn中的函数指针指向静态函数。

    H

    struct Data {
        int i;
        int *array;
    };
    
    typedef struct {
        bool (* const fn1) (struct Data*, const char *source);
        ....
    } DataFn;
    extern DataFn const DATAFUNC
    

    使用objdump,该表只包含DATAFUNC和gcc中的一些其他内容。

    在C语言中,调用fn1就像调用DATAFUNC一样,这很好。fn1(…,…),但是,如何包装这样的内容,以便在python w/C类型中调用fn1呢?

    python示例

    libc = ctypes.cdll.LoadLibrary("./data.so")
    print(libc.DATAFUNC)
    

    结果在 <_FuncPtr object at 0x6ffffcd7430>

    This is similar, but there isn't a factory function.

    1 回复  |  直到 6 年前
        1
  •  2
  •   CristiFati    5 年前

    [Python 3.Docs]: ctypes - A foreign function library for Python 包含解决此问题所需的所有内容。

    我认为丢失的主要部分是 in\u dll a的方法 C类型 类型( 访问从dll导出的值 第节)。

    除此之外,为了 C 数据,您需要 python 了解数据格式。适用于:

    • 结构 s、 定义 python 按子类划分的副本 ctypes.Structure
    • 函数指针(适用于您的案例)。使用定义它们 ctypes.CFUNCTYPE

    我准备了一个简单的示例来说明上述内容。注意,我没有做任何错误处理(检查 无效的 s(其中 你应该 )),使事情变得简单。

    c、 h类 :

    struct Data {
        int i;
    };
    
    
    typedef struct {
        int (* const fn1) (struct Data*, const char*);
    } DataFn;
    
    
    extern DataFn const DATAFUNC;
    

    c、 c类 :

    #include <stdio.h>
    #include "c.h"
    
    
    static int func1(struct Data *pData, const char *source) {
        printf("From C - Data.i: [%d], source: [%s]\n", pData->i, source);
        return -255;
    }
    
    
    DataFn const DATAFUNC = {&func1};
    

    代码00。py公司 :

    #!/usr/bin/env python3
    
    
    import sys
    from ctypes import c_int, c_char_p, Structure, CDLL, CFUNCTYPE, POINTER, byref
    
    
    class Data(Structure):
        _fields_ = [
            ("i", c_int),
        ]
    
    
    fn1_type = CFUNCTYPE(c_int, POINTER(Data), c_char_p)
    
    
    class DataFn(Structure):
        _fields_ = [
            ("fn1", fn1_type),
        ]
    
    
    def main():
        data = Data(127)
        dll = CDLL("./c.so")
        data_func = DataFn.in_dll(dll, "DATAFUNC")
        ret = data_func.fn1(byref(data), "abcd".encode())
        print("DATAFUNC.fn1 returned {:d}".format(ret))
    
    
    if __name__ == "__main__":
        print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
        main()
    

    输出 :

    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049962265]> ls
    c.c  c.h  code00.py
    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049962265]> gcc -shared -fPIC -o c.so c.c
    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049962265]> ls
    c.c  c.h  code.py  c.so
    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049962265]> objdump -t c.so | grep DATAFUNC
    0000000000200e10 g     O .data.rel.ro   0000000000000008              DATAFUNC
    [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049962265]> python3 code00.py
    Python 3.5.2 (default, Nov 23 2017, 16:37:01)
    [GCC 5.4.0 20160609] on linux
    
    From C - Data.i: [127], source: [abcd]
    DATAFUNC.fn1 returned -255