当前位置: 首页 > 工具软件 > CFFI > 使用案例 >

python cffi的使用初探

陶高峯
2023-12-01

废话不多说, 直接上代码(忽略我写的c代码严谨性, 我刚学的c)

//  hello.h
// Created by 86176 on 2022/12/14.
//

#ifndef UNTITLED1_SAMPLE_H
#define UNTITLED1_SAMPLE_H
typedef struct {
    int x,y;
} Point;

typedef struct {
    int data1;
    float *data2;
    double *data3;
    int data4[3];
    char *data5;
    char data6[10];

} FuncResult;


FuncResult test_func(int data1, float *data2, double *data3, int data4[], char *data5, char data6[]);


void register_callback(int d, void (*func)(Point *p));

void struct_func(int d, Point *p);


#endif //UNTITLED1_SAMPLE_H

c代码编译成libhello.dll

# sample.py
import array
import ctypes
import os

_file = 'libhello.dll'
_path = os.path.join(*(os.path.split(__file__)[:-1] + (_file,)))

import cffi
import platform


ffi = cffi.FFI()


def load_library():
    lib_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)))

    # # 1. load header
    with open(os.path.join(lib_dir, "library.h"), encoding='utf-8') as sdk_header:
        sdk_header = sdk_header.read() \
            .split("#define UNTITLED1_SAMPLE_H")[1]                           \
            .replace("#endif", "")
        ffi.cdef(sdk_header)

    # 2. find library path and load
    arch = platform.architecture()[0]
    if platform.system() == "Darwin":
        return ffi.dlopen(os.path.join(lib_dir, "libhello.dll"))

    elif platform.system() == "Windows" and arch == "64bit":
        # add path 'python/libemgp/' to environment variable 'PATH' to load the dependent DLLs.
        os.environ["PATH"] += os.pathsep + os.path.join(lib_dir, "win")
        # return ffi.dlopen(os.path.join(lib_dir, "win", "emgp.dll"))
        return ffi.dlopen(os.path.join(lib_dir, "libhello.dll"))
    else:
        raise Exception("Unsupported platform: " + platform.system() + ", arch: " + arch)


# load EMGPlusSDK library
libemgp = load_library()
# FuncResult test_func(int x, float *y, const double z[10], char c, char *data1, const char data2[10], Point *p);

data1 = 1
data2 = ffi.new('float *', 1)
data3 = ffi.new('double *', 1)
data4 = [1, 2, 3]
data5 = ffi.new('char *', 'a'.encode())
data6 = ffi.new('char []', 'hello world'.encode('utf-8'))

res = libemgp.test_func(data1, data2, data3, data4, data5, data6)

print('------------------函数传参-----------------------------')
print(res.data1)
print(res.data2[0])  # print(ffi.unpack(res.data2, 1)[0])
print(res.data3[0])  # print(ffi.unpack(res.data3, 1)[0])
print(ffi.unpack(res.data4, 3))
print(ffi.unpack(res.data5, 1).decode('utf-8'))  # print(ffi.string(res.data5).decode('utf-8'))
print(ffi.unpack(res.data6, len("hello world")).decode('utf-8'))  # print(ffi.string(res.data6).decode('utf-8'))


print('------------------函数回调-----------------------------')


@ffi.callback("void(Point *p)")
def func_callback(point):
    print(point.x)
    print(point.y)


libemgp.register_callback(3, func_callback)


print('------------------结构体参数-----------------------------')

libemgp.struct_func(2, ffi.new("Point *", (3, 4)))

对比ctypes可以看到cffi的代码更简洁一点, 更加靠近python的语法, 缺点就是教程太少了, 包括官方的教程也是错误一大堆(好像教程是老版本的, cffi==1.15.1运行例子不少报错的)

附上cffi官方教程链接

 类似资料: