如何通过void指针访问传入函数的函数指针数组元素?
如何通过void*传递函数指针数组并访问其元素?
问题背景
因使用LVGL图形库,必须通过lv_obj_add_event_cb(obj, callback_fn, my_event_trigger, user_data)以void*类型传递函数指针数组作为user_data。触发事件时在回调函数中通过lv_event_get_user_data(e)获取该数组,但无法直接访问数组元素并调用对应函数。
现有可正常运行的示例
示例1:通过void*传递普通数组
#include <stdio.h> void function(void* ptr) { int* arr = ptr; for(int i = 0; i < 5; ++i) { printf("%d ", arr[i]); } } int main() { int arr_nums[5] = { 1, 2, 3, 4, 5 }; function((void*)arr_nums); return 0; }
输出:
1 2 3 4 5
示例2:通过void*传递单个函数指针
#include <stdio.h> int add(int a, int b) { return (a + b); } int sub(int a, int b) { return (a - b); } int mult(int a, int b) { return (a * b); } int divide(int a, int b) { return (a / b); } int function(void *ptr) { return ((int(*)(int, int))ptr)(4, 2); } int main() { printf("%d\n", function((void*)add)); printf("%d\n", function((void*)sub)); printf("%d\n", function((void*)mult)); printf("%d\n", function((void*)divide)); return 0; }
输出:
6 2 8 2
示例3:通过void*传递函数指针数组的单个元素
// 复用示例2中的add/sub/mult/divide函数和function函数 int main() { int (* fp_arr[4])(int, int) = { add, sub, mult, divide }; printf("%d\n", function((void*)fp_arr[0])); printf("%d\n", function((void*)fp_arr[1])); printf("%d\n", function((void*)fp_arr[2])); printf("%d\n", function((void*)fp_arr[3])); return 0; }
输出:
6 2 8 2
问题场景:传递整个函数指针数组并访问元素
需要修改function函数,实现通过传入的void*访问函数指针数组的指定元素(比如调用下标为2的mult函数):
// 复用add/sub/mult/divide函数 int function(void *ptr) { // 如何实现类似ptr[2]调用mult的操作? return ((int(*)(int, int))ptr)(4, 2); } int main() { int (* fp_arr[4])(int, int) = { add, sub, mult, divide }; printf("%d\n", function((void*)fp_arr)); return 0; }
解决方案
核心是将void*转换为指向函数指针的指针或指向函数指针数组的指针,之后即可像普通数组一样通过下标访问元素。
方法1:转换为指向函数指针的指针
数组名传递时会退化为指向第一个元素的指针,所以我们可以把void*转换为int(**)(int, int)(即指向函数指针的指针),之后直接用下标访问:
int function(void *ptr) { // 将void*转换为指向函数指针的指针 int (**fp_ptr)(int, int) = (int (**)(int, int))ptr; // 访问数组第2个元素(下标从0开始)并调用 return fp_ptr[2](4, 2); }
方法2:转换为指向函数指针数组的指针
也可以直接转换为指向整个函数指针数组的指针,解引用后得到数组再访问元素:
int function(void *ptr) { // 将void*转换为指向函数指针数组的指针 int (*(*fp_arr)[4])(int, int) = (int (*(*)[4])(int, int))ptr; // 解引用得到数组,再访问第2个元素并调用 return (*(*fp_arr)[2])(4, 2); }
两种方法都能实现需求,方法1更简洁,适合大多数场景。
内容的提问来源于stack exchange,提问作者cmoran
相关产品推荐
相关产品推荐

