Cython官方文档中文翻译:调用C函数

  • 说明

    尝试翻译Cython Documentation以助学习。

    水平有限,乐迎指正;文档首页:《Cython官方文档中文翻译

  • 调用C函数

    此教程简述了从Cython代码中调用C库函数的必要知识,关于使用额外C库封装处理错误的更深入理解,参见Using C libraries

    简单起见,从C标准库中的一个函数开始。这不会向代码添加任何依赖性,还有个额外优势,就是Cython已经为你定义了很多类似函数。因此你只需cimport并使用。

    例如,假设你需要一种低级的方式来对char*值解析出数。你可以用stdlib.h头文件定义的*atoi()*函数,操作如下:

    from libc.stdlib cimport atoi
    
    cdef parse_charptr_to_py_int(char* s):
        assert s is not NULL, "byte string value is NULL"
        return atoi(s) # atoi()函数没有错误检查机制
    

    你可以在Cython的源文件Cython/Includes/中找到这些标准cimport文件的完整列表。他们存储在*.pyx文件中,提供可跨模块共享可复用的Cython声明*的标准方式。(详情参见 Sharing Declarations Between Cython Modules

    Cython也有完整一套用于CPythonC-API的声明,例如,为测试在C编译时你的代码正用CPython的哪个版本编译,你可以:

    from cpython.version cimport PY_VERSION_HEX
    print(PY_VERSION_HEX >= 0x030200F0)
    

    Cython还提供对C数学库的声明:

    from libc.math cimport sin
    cdef double f(double x):
        return sin(x * x)
    
  • 动态链接

    libc数学库的独特在于,在某些类Unix系统上,未链接它,比如Linux。为cimport这些声明,你必须配置构建系统以链接共享库m。对于distutils,只需将其添加到Extension()设置的libraries参数:

    from distutils.core import setup
    from distutils.extension import Extension
    from Cython.Build import cythonize
    ext_modules = [
        Extension("demo",
                 source = ["demo.pys"],
                 libraries = ["m"])   # 类Unix特有
    ]
    setup(name="Demos",ext_modules = cythonize(ext_modules))
    
  • 其他声明

    如果你想访问Cython没有直接备好声明的C代码,你必须自己声明它。例如,前面提到的*sin()*函数定义方式如下:

    cdef extern from "math.h":
        double sin(double x)
    

    上述代码声明了sin()函数,使之可用于Cython代码,并指示Cython在生成C代码时包含math.h头文件。C编译器在编译过程中会识别math.h文件中的原始声明,然而Cython并不会解析*“math.h”*因此需要一个单独的声明。

    就像math库中的sin()函数,只要Cython生成的模块正确链接共享库静态库,就可以声明或调用任何C库

    你可以通过声明cpdef,从Cython模块中输出任何C函数。这将为它生成一个Python包装器,并添加到module dict中。下面是一个Cython模块,它实现了Python代码直接访问C *sin()*函数:

    """
    >>> sin(0)
    0.0
    """
    cdef extern from "math.h":
        cpdef double sin(double x)
    

    如果上述声明出现在属于Cython模块(详情参见 Sharing Declarations Between Cython Modules)的*.pyd*文件中效果是一样的。

    这允许Cython模块复用C声明,同时在这个特殊模块中自动生成Python包装器

  • 命名参数

    CCython都支持像这样没有参数的签名声明:

    cdef extern from "string.h":
        char* strstr(const char*, const char*)
    

    但是,这可以防止Cython代码使用关键字参数调用它。因此下面写法更优:

    cdef extern from "string.h":
        char* strstr(const char *haystack, const char *needle)
    

    这样就很清楚在调用中这两个参数各自做了什么,避免歧义同时增加代码可读性:

    cdef extern from "string.h":
        char* strstr(const char *haystack, const char *needle)
    cdef char* data = "hfvcakdfagbcffvschvxcdfgccbcfhvgcsnfxjh"
    cdef char* pos = strstr(needle= "akd", haystack= data)
    print(pos is not NULL)
    

    后续更变已存在参数是一种后向不兼容API修改,就如Python代码。因此,如果你自定义CC++函数声明,通常值得花费额外的精力来选择他们的参数名。

  • References

  1. 本文链接
发布了753 篇原创文章 · 获赞 1021 · 访问量 54万+

猜你喜欢

转载自blog.csdn.net/The_Time_Runner/article/details/103672347