cython如何调用C语言的函数?_c 中如何调用python
在 Cython 中调用 C 语言函数主要通过以下几种方式实现:
1. 使用 cdef extern 声明外部 C 函数
基本语法
cdef extern from "头文件.h":
返回类型 函数名(参数类型1, 参数类型2, ...)
示例:调用标准 C 库函数
# 声明 math.h 中的函数
cdef extern from "math.h":
double sin(double x)
double cos(double x)
double sqrt(double x)
# 使用这些函数
def calculate_trig(double angle):
cdef double result = sin(angle) + cos(angle)
return result
2. 使用 Cython 预定义的标准库模块
Cython 提供了许多预定义的 .pxd 文件,可以直接导入使用:
调用标准 C 库函数
from libc.math cimport sin, cos, sqrt
from libc.stdio cimport printf
from libc.stdlib cimport malloc, free
def demo_standard_c():
cdef double x = 3.14159 / 4
cdef double result = sin(x) + cos(x)
# 调用 printf
printf("Result: %f\n", result)
# 动态内存分配
cdef int* arr = <int*>malloc(10 * sizeof(int))
if arr != NULL:
free(arr)
return result
3. 调用自定义 C 函数
步骤 1:创建 C 头文件 (mylib.h)
// mylib.h
#ifndef MYLIB_H
#define MYLIB_H
int add(int a, int b);
double multiply(double a, double b);
void print_message(const char* message);
#endif
步骤 2:创建 C 源文件 (mylib.c)
// mylib.c
#include <stdio.h>
#include "mylib.h"
int add(int a, int b) {
return a + b;
}
double multiply(double a, double b) {
return a * b;
}
void print_message(const char* message) {
printf("Message: %s\n", message);
}
步骤 3:在 Cython 中声明和调用
# mymodule.pyx
cdef extern from "mylib.h":
int add(int a, int b)
double multiply(double a, double b)
void print_message(const char* message)
def py_add(int a, int b):
return add(a, b)
def py_multiply(double a, double b):
return multiply(a, b)
def py_print_message(message):
# 将 Python 字符串转换为 C 字符串
cdef bytes msg_bytes = message.encode('utf-8')
cdef char* c_msg = msg_bytes
print_message(c_msg)
4. 处理指针和复杂数据类型
调用返回指针的函数
cdef extern from "mylib.h":
int* create_int_array(int size)
void free_int_array(int* arr)
def create_array(int size):
cdef int* arr = create_int_array(size)
if arr == NULL:
raise MemoryError("Failed to allocate array")
# 将 C 数组转换为 Python 列表
result = []
for i in range(size):
result.append(arr[i])
free_int_array(arr)
return result
调用结构体相关的函数
cdef extern from "mylib.h":
struct Point:
double x
double y
double distance(Point* p1, Point* p2)
Point* create_point(double x, double y)
def calculate_distance(double x1, double y1, double x2, double y2):
cdef Point* p1 = create_point(x1, y1)
cdef Point* p2 = create_point(x2, y2)
if p1 == NULL or p2 == NULL:
raise MemoryError("Failed to create points")
cdef double dist = distance(p1, p2)
# 需要相应的释放函数
# free_point(p1)
# free_point(p2)
return dist
5. 使用 cpdef 导出 C 函数给 Python
cdef extern from "mylib.h":
int add(int a, int b)
# 同时提供 C 和 Python 接口
cpdef int cpdef_add(int a, int b):
return add(a, b)
6. 错误处理和异常
使用 except 子句处理 C 函数错误
cdef extern from "mylib.h":
int risky_function() except -1 # 返回 -1 表示错误
def safe_function():
cdef int result = risky_function()
if result == -1:
raise RuntimeError("C function failed")
return result
使用 except * 处理可能抛出异常的函数
cdef extern from "mylib.h":
int might_fail() except *
def try_function():
cdef int result = might_fail()
return result
7. 编译和链接设置
setup.py 配置
from setuptools import Extension, setup
from Cython.Build import cythonize
extensions = [
Extension(
"mymodule",
sources=["mymodule.pyx", "mylib.c"], # 包含 C 源文件
include_dirs=["."], # 包含头文件目录
# 如果需要链接外部库
# libraries=["m"],
# library_dirs=["/path/to/lib"],
)
]
setup(
name="My Module",
ext_modules=cythonize(extensions),
)
8. 完整示例
C 代码 (mylib.h 和 mylib.c)
// mylib.h
#ifndef MYLIB_H
#define MYLIB_H
typedef struct {
double x;
double y;
} Vector2D;
Vector2D* create_vector(double x, double y);
double vector_length(Vector2D* vec);
void free_vector(Vector2D* vec);
#endif
// mylib.c
#include <math.h>
#include <stdlib.h>
#include "mylib.h"
Vector2D* create_vector(double x, double y) {
Vector2D* vec = malloc(sizeof(Vector2D));
if (vec) {
vec->x = x;
vec->y = y;
}
return vec;
}
double vector_length(Vector2D* vec) {
return sqrt(vec->x * vec->x + vec->y * vec->y);
}
void free_vector(Vector2D* vec) {
free(vec);
}
Cython 代码
# vector_module.pyx
cdef extern from "mylib.h":
struct Vector2D:
double x
double y
Vector2D* create_vector(double x, double y)
double vector_length(Vector2D* vec)
void free_vector(Vector2D* vec)
def create_py_vector(double x, double y):
cdef Vector2D* vec = create_vector(x, y)
if vec == NULL:
raise MemoryError("Failed to create vector")
try:
length = vector_length(vec)
return {"x": vec.x, "y": vec.y, "length": length}
finally:
free_vector(vec)
cpdef double calculate_length(double x, double y):
cdef Vector2D* vec = create_vector(x, y)
if vec == NULL:
raise MemoryError("Failed to create vector")
try:
return vector_length(vec)
finally:
free_vector(vec)
关键注意事项
1. 内存管理:确保正确释放 C 函数分配的内存
2. 类型转换:注意 Python 类型和 C 类型之间的转换
3. 错误处理:适当处理 C 函数可能返回的错误
4. 线程安全:确保在多线程环境中安全调用 C 函数
5. 编译链接:正确配置编译选项和链接库
通过以上方法,您可以在 Cython 中灵活地调用各种 C 语言函数,实现高性能的混合编程。