繁体   English   中英

C 到 Python 通过 Ctypes - Function 指针的包装结构

[英]C to Python via Ctypes - Wrapping Struct of Function Pointers to Static Functions

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

。H

struct Data {
    int i;
    int *array;
};

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

使用 objdump,该表仅包含来自 gcc 的 DATAFUNC 和其他一些内容。

这在 C 中很好,其中调用 fn1 会像 DATAFUNC.fn1(..., ...) 一样调用 go,但是如何将这样的东西包裹起来,所以 fn1 可以在 Z23EEEB4347BDD756BFC6B7EEsD9 中调用?

示例 python

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

结果<_FuncPtr object at 0x6ffffcd7430>

这类似,但没有工厂 function。

[Python.Docs]: ctypes - 用于 Python 的外国 function 库包含解决此问题所需的一切。

我相信缺少的主要部分是CTypes类型的in_dll方法(访问从 dll 部分导出的值)。

除此之外,为了使用C数据,您需要让Python知道数据格式。 这适用于:

  • 结构s。 通过子类化 ctypes.Structure来定义Python对应物

  • Function 指针(适用于您的情况)。 使用ctypes.CFUNCTYPE定义它们

我准备了一个简化的示例来说明上述内容。 请注意,为了简单起见,我没有进行任何错误处理(检查NULL您应该这样做))。

dll00.h

struct Data {
    int i;
};


typedef struct {
    int (* const Func00Ptr) (struct Data*, const char*);
} DataFunc;


extern DataFunc const dataFunc;

dll00.c

#include <stdio.h>

#include "dll00.h"


static int func00(struct Data *pData, const char *source)
{
    printf("From C - Data.i: [%d], source: [%s]\n", pData->i, source);
    return -255;
}


DataFunc const dataFunc = { &func00 };

代码00.py

#!/usr/bin/env python

import ctypes as ct
import sys


DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")


class Data(ct.Structure):
    _fields_ = (
        ("i", ct.c_int),
    )


Func00Type = ct.CFUNCTYPE(ct.c_int, ct.POINTER(Data), ct.c_char_p)


class DataFunc(ct.Structure):
    _fields_ = (
        ("func00", Func00Type),
    )


def main(*argv):
    data = Data(127)
    dll = ct.CDLL(DLL_NAME)
    data_func = DataFunc.in_dll(dll, "dataFunc")
    ret = data_func.func00(ct.byref(data), "abcd".encode())
    print("Function returned: {:d}".format(ret))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

Output

 [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049962265]> ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> ls dll00.c dll00.h code00.py [064bit prompt]> gcc -shared -fPIC -o dll00.so dll00.c [064bit prompt]> ls dll00.c dll00.h code.py dll00.so [064bit prompt]> objdump -t dll00.so | grep dataFunc 0000000000200e10 g O.data.rel.ro 0000000000000008 dataFunc [064bit prompt]> python code00.py Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit on linux From C - Data.i: [127], source: [abcd] Function returned: -255 Done.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM