如何用CFFI传递指针给会修改指针的C函数?
问题分析与解决:CFFI调用返回数组的C函数
1. 原C函数的致命错误
原函数中的float result[4]是栈上的局部变量,函数执行完毕后栈帧会被销毁,这块内存会被操作系统回收或覆盖。此时把&result赋值给*outputArr,本质是返回了一块已失效的内存地址——原C代码看似能输出正确值只是巧合(栈内存还没被覆盖),实际属于未定义行为,后续必然会出问题。
2. 修正C函数的正确写法
要让返回的数组有效,必须使用堆内存分配(malloc),或者让调用者预先提供缓冲区。这里推荐堆分配的方式:
#include <stdlib.h> int generateFloatArr(float **outputArr) { // 动态分配4个float的内存 float *result = malloc(4 * sizeof(float)); if (result == NULL) return -1; // 内存分配失败时返回错误码 // 初始化数组 result[0] = 1.0f; result[1] = 2.0f; result[2] = 3.0f; result[3] = 4.0f; *outputArr = result; return 4; // 返回数组长度 }
注意:调用该函数后,必须手动调用
free()释放内存,避免内存泄漏。
3. C语言的正确调用示例
#include <stdio.h> #include <stdlib.h> int main() { float *output; int arrLen = generateFloatArr(&output); if (arrLen > 0) { printf("%f \n", output[0]); // 正确输出1.000000 free(output); // 释放堆内存 } return 0; }
4. CFFI的正确调用方式
方式一:创建float**指针调用
import cffi # 初始化CFFI ffi = cffi.FFI() ffi.cdef(""" int generateFloatArr(float **outputArr); """) # 加载编译好的共享库(替换为你的库路径) lib = ffi.dlopen("./libyourfunc.so") # 创建指向float指针的指针 p_p_float = ffi.new("float **") arr_len = lib.generateFloatArr(p_p_float) if arr_len > 0: # 获取返回的数组指针 output_arr = p_p_float[0] print(output_arr[0]) # 输出1.0 # 释放堆内存 ffi.free(output_arr)
方式二:用ffi.addressof获取指针地址
先创建一个float*变量,再通过ffi.addressof获取它的地址(即float**类型)传入函数:
import cffi ffi = cffi.FFI() ffi.cdef(""" int generateFloatArr(float **outputArr); """) lib = ffi.dlopen("./libyourfunc.so") # 创建一个float指针变量(无需分配内存,函数会赋值堆指针) p_float = ffi.new("float *") # 传入p_float的地址(类型为float**) arr_len = lib.generateFloatArr(ffi.addressof(p_float)) if arr_len > 0: print(p_float[0]) # 输出1.0 ffi.free(p_float) # 释放内存
5. 原调用错误的原因
- 你尝试的错误C调用
float **output; generateFloatArr(output);中,output是未初始化的野指针,函数内部给*outputArr赋值时会访问非法内存,触发段错误。 - 原CFFI调用得到错误值,是因为原函数返回的栈内存地址已失效,访问时读取的是被覆盖的垃圾数据。
内容的提问来源于stack exchange,提问作者davegravy
相关产品推荐
相关产品推荐

