利用Python CFFI进行原子级别的C库调用

介绍

Python是一种高级语言,常用于快速开发、数据挖掘等领域,但有时候需要借助C库进行密集计算等操作。Python提供了很多种方式进行C库调用,例如ctypes、Swig等,但各种方式都存在一些问题。CFFI是Python官方推荐的C库调用方式,提供了原子级别的C库调用能力,一致性强,灵活性高,效率较高,已被广泛应用于NumPy、PyPy、Pillow等多个Python库。

正文

一、CFFI的基础使用

使用CFFI调用C库的过程包括三步:

  1. 定义C函数接口
  2. from cffi import FFI
    
    ffi = FFI()
    
    lib = ffi.dlopen('libc.so.6')
    
    # 定义C函数接口
    # void 则表示没有返回值
    # int 则表示返回值类型是整数
    # int, int 表示C函数接收两个整数类型的参数
    add = lib.printf
    add.argtypes = ffi.typeof("char *")
    add.restype = ffi.typeof("int")
  3. 调用C函数接口
  4. # 调用C函数接口
    result = add(b"Hello World")
    print(result)
  5. 编译代码
  6. gcc -shared -o libtest.so test.c

二、CFFI与ctypes的比较

ctypes是Python内置的C库调用方式,也是使用比较广泛的一种方式,但与CFFI相比还是存在一些差异:

  • 使用方式:CFFI要求对C语言的代码重构最小,而ctypes则要求用户按照ctypes的规范来组织C代码。
  • 兼容性:CFFI兼容性良好,支持多个平台,而ctypes不一定能够在所有平台上正常使用。
  • Python版本:CFFI仅支持Python2.6、Python2.7、Python3.2以及更高版本,而ctypes作为Python内置库则兼容Python2.6 ~ Python3.x各版本。

三、CFFI的高级使用

除了基本的C库调用之外,CFFI还提供了一些高级功能,例如:

  • Struct类型的支持
  • from cffi import FFI
    
    ffi = FFI()
    
    cpp_code = '''
    #include 
    #include 
    
    struct PointF {
        float x;
        float y;
    };
    
    typedef struct PointF PointF;
    
    void show_point(PointF p) {
        printf("%0.1f, %0.1f", p.x, p.y);
    }'''
    
    # 声明C数据结构
    ffi.cdef("""
        typedef struct {
            float x;
            float y;
        } PointF;
        void show_point(PointF);
    """)
    
    lib = ffi.verify(cpp_code, libraries=[])
    p = ffi.new('PointF*', [1.5, 2.4])
    lib.show_point(p[0])
  • Union类型的支持
  • from cffi import FFI
    
    ffi = FFI()
    
    cpp_code = '''
    #include 
    
    union Shape {
        int shape_type;
        struct {
            int x;
            int y;
            int width;
            int height;
        } rect;
    };
    
    typedef union Shape Shape;
    
    void show_rect(Shape r) {
        printf("(%d, %d, %d, %d)",
            r.rect.x, r.rect.y, r.rect.width, r.rect.height);
    }'''
    
    ffi.cdef("""
        typedef union {
            int shape_type;
            struct {
                int x;
                int y;
                int width;
                int height;
            } rect;
        } Shape;
        void show_rect(Shape);
    """)
    
    lib = ffi.verify(cpp_code, libraries=[])
    s = ffi.new('Shape*', [0])
    s.rect.x = 1
    s.rect.y = 2
    s.rect.width = 3
    s.rect.height = 4
    lib.show_rect(s[0])

代码部分

以下是一个使用CFFI调用Windows API的例子:

# -*- coding: utf-8 -*-

from cffi import FFI

# 定义C函数接口
ffi = FFI()
ffi.cdef("""
    typedef struct _FILETIME {
        unsigned long dwLowDateTime;
        unsigned long dwHighDateTime;
    } FILETIME, *PFILETIME, *LPFILETIME;

    typedef struct _SYSTEMTIME {
        short wYear;
        short wMonth;
        short wDayOfWeek;
        short wDay;
        short wHour;
        short wMinute;
        short wSecond;
        short wMilliseconds;
    } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;

    void GetSystemTime(SYSTEMTIME *lpSystemTime);
    void SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime, LPFILETIME lpFileTime);
    void FileTimeToLocalFileTime(CONST FILETIME *lpFileTime, LPFILETIME lpLocalFileTime);
    BOOL FileTimeToSystemTime(const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime);
""")

lib = ffi.dlopen('kernel32.dll')

# 调用GetSystemTime函数,获取当前系统时间(UTC)
system_time = ffi.new('SYSTEMTIME *')
lib.GetSystemTime(system_time)

# 将UTC时间转换为本地时间
file_time_utc = ffi.new('FILETIME *')
lib.SystemTimeToFileTime(system_time, file_time_utc)
file_time_local = ffi.new('FILETIME *')
lib.FileTimeToLocalFileTime(file_time_utc, file_time_local)

# 获取系统时间(本地时间)
local_time = ffi.new('SYSTEMTIME *')
lib.FileTimeToSystemTime(file_time_local, local_time)

print('Local Time:', local_time.wYear, local_time.wMonth, local_time.wDay, local_time.wHour, local_time.wMinute, local_time.wSecond, local_time.wMilliseconds)

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/257975.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-15 12:47
下一篇 2024-12-15 12:47

相关推荐

  • Python计算阳历日期对应周几

    本文介绍如何通过Python计算任意阳历日期对应周几。 一、获取日期 获取日期可以通过Python内置的模块datetime实现,示例代码如下: from datetime imp…

    编程 2025-04-29
  • 如何查看Anaconda中Python路径

    对Anaconda中Python路径即conda环境的查看进行详细的阐述。 一、使用命令行查看 1、在Windows系统中,可以使用命令提示符(cmd)或者Anaconda Pro…

    编程 2025-04-29
  • Python中引入上一级目录中函数

    Python中经常需要调用其他文件夹中的模块或函数,其中一个常见的操作是引入上一级目录中的函数。在此,我们将从多个角度详细解释如何在Python中引入上一级目录的函数。 一、加入环…

    编程 2025-04-29
  • Python列表中负数的个数

    Python列表是一个有序的集合,可以存储多个不同类型的元素。而负数是指小于0的整数。在Python列表中,我们想要找到负数的个数,可以通过以下几个方面进行实现。 一、使用循环遍历…

    编程 2025-04-29
  • Python周杰伦代码用法介绍

    本文将从多个方面对Python周杰伦代码进行详细的阐述。 一、代码介绍 from urllib.request import urlopen from bs4 import Bea…

    编程 2025-04-29
  • python强行终止程序快捷键

    本文将从多个方面对python强行终止程序快捷键进行详细阐述,并提供相应代码示例。 一、Ctrl+C快捷键 Ctrl+C快捷键是在终端中经常用来强行终止运行的程序。当你在终端中运行…

    编程 2025-04-29
  • Python字典去重复工具

    使用Python语言编写字典去重复工具,可帮助用户快速去重复。 一、字典去重复工具的需求 在使用Python编写程序时,我们经常需要处理数据文件,其中包含了大量的重复数据。为了方便…

    编程 2025-04-29
  • Python清华镜像下载

    Python清华镜像是一个高质量的Python开发资源镜像站,提供了Python及其相关的开发工具、框架和文档的下载服务。本文将从以下几个方面对Python清华镜像下载进行详细的阐…

    编程 2025-04-29
  • Python程序需要编译才能执行

    Python 被广泛应用于数据分析、人工智能、科学计算等领域,它的灵活性和简单易学的性质使得越来越多的人喜欢使用 Python 进行编程。然而,在 Python 中程序执行的方式不…

    编程 2025-04-29
  • 蝴蝶优化算法Python版

    蝴蝶优化算法是一种基于仿生学的优化算法,模仿自然界中的蝴蝶进行搜索。它可以应用于多个领域的优化问题,包括数学优化、工程问题、机器学习等。本文将从多个方面对蝴蝶优化算法Python版…

    编程 2025-04-29

发表回复

登录后才能评论