You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C语言中value_info数组转为函数实参并调用指定函数?

解决方案:C语言中基于函数表的动态参数调用

由于C是静态编译型语言,无法直接实现完全通用的任意参数个数/类型的动态调用,只能通过预定义参数个数分支+运行时类型判断的方式实现最多10个参数的调用支持。以下是具体实现方案:

核心思路

  1. 先通过函数名字符串从函数表中找到对应的function_info结构体。
  2. 根据function_info记录的参数个数(argc)和参数类型(argv数组),从value_info参数数组中提取并转换参数。
  3. 针对不同参数个数编写分支逻辑,转换函数指针为正确类型后调用,并处理返回值。

完整实现代码

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>

// 类型定义(复用你提供的代码)
typedef int int_type;
typedef float float_type;
typedef double double_type;
typedef bool bool_type;
typedef char *string_type;

typedef enum {
    INT_TYPE,
    FLOAT_TYPE,
    DOUBLE_TYPE,
    BOOL_TYPE,
    STRING_TYPE,
} data_type;

typedef struct function_info function_info;

typedef struct {
    data_type type;
    union {
        int_type val_int;
        float_type val_float;
        double_type val_double;
        bool_type val_bool;
        string_type val_string;
        function_info val_function;
    } value;
} value_info;

#define MAX_ARGS 10

struct function_info {
    union {
        int (*f_int)();
        float (*f_float)();
        double (*f_double)();
        bool (*f_bool)();
        char *(*f_string)();
    } function;
    int argc;
    data_type argv[MAX_ARGS];
    data_type ret_type;
};

struct init {
    char *fname;
    function_info fnct;
};

struct init arith_fncts[] = {
    {"sin", {.function.f_double = sin, 1, {DOUBLE_TYPE}, DOUBLE_TYPE}},
    {"cos", {.function.f_double = cos, 1, {DOUBLE_TYPE}, DOUBLE_TYPE}},
    {"tan", {.function.f_double = tan, 1, {DOUBLE_TYPE}, DOUBLE_TYPE}}};

// 辅助函数:将value_info转换为double类型参数
double get_double_arg(value_info *arg) {
    switch(arg->type) {
        case INT_TYPE: return (double)arg->value.val_int;
        case FLOAT_TYPE: return (double)arg->value.val_float;
        case DOUBLE_TYPE: return arg->value.val_double;
        case BOOL_TYPE: return (double)arg->value.val_bool;
        default:
            fprintf(stderr, "Error: Cannot convert argument to double\n");
            return 0.0;
    }
}

// 辅助函数:将value_info转换为int类型参数
int get_int_arg(value_info *arg) {
    switch(arg->type) {
        case INT_TYPE: return arg->value.val_int;
        case FLOAT_TYPE: return (int)arg->value.val_float;
        case DOUBLE_TYPE: return (int)arg->value.val_double;
        case BOOL_TYPE: return (int)arg->value.val_bool;
        default:
            fprintf(stderr, "Error: Cannot convert argument to int\n");
            return 0;
    }
}

// 根据函数名查找函数表中的function_info
function_info* find_function(const char *fname) {
    size_t fn_count = sizeof(arith_fncts) / sizeof(arith_fncts[0]);
    for(size_t i = 0; i < fn_count; i++) {
        if(strcmp(arith_fncts[i].fname, fname) == 0) {
            return &arith_fncts[i].fnct;
        }
    }
    fprintf(stderr, "Error: Function '%s' not found\n", fname);
    return NULL;
}

// 调用函数并返回结果(支持0-10个参数,这里实现了1个参数的示例,可扩展)
value_info call_function(function_info *fn, value_info args_array[]) {
    value_info result = {.type = fn->ret_type};

    switch(fn->argc) {
        // 0个参数的情况
        case 0:
            switch(fn->ret_type) {
                case INT_TYPE: result.value.val_int = fn->function.f_int(); break;
                case DOUBLE_TYPE: result.value.val_double = fn->function.f_double(); break;
                default:
                    fprintf(stderr, "Error: Unsupported return type for 0-arg function\n");
                    result.type = -1;
            }
            break;
        // 1个参数的情况
        case 1:
            switch(fn->ret_type) {
                case DOUBLE_TYPE:
                    if(fn->argv[0] == DOUBLE_TYPE) {
                        result.value.val_double = fn->function.f_double(get_double_arg(&args_array[0]));
                    } else if(fn->argv[0] == INT_TYPE) {
                        result.value.val_double = ((double(*)(int))fn->function.f_double)(get_int_arg(&args_array[0]));
                    } else {
                        fprintf(stderr, "Error: Unsupported argument type for 1-arg function\n");
                        result.type = -1;
                    }
                    break;
                default:
                    fprintf(stderr, "Error: Unsupported return type for 1-arg function\n");
                    result.type = -1;
            }
            break;
        // 扩展2-10个参数的分支逻辑,格式参考case 1
        // case 2: ...
        // case 3: ...
        // ...
        // case 10: ...
        default:
            fprintf(stderr, "Error: Unsupported argument count (%d)\n", fn->argc);
            result.type = -1;
            break;
    }

    return result;
}

// 测试示例
int main() {
    // 准备参数:sin(π/2)
    value_info args_array[10];
    args_array[0].type = DOUBLE_TYPE;
    args_array[0].value.val_double = M_PI / 2;

    function_info *fn = find_function("sin");
    if(fn) {
        value_info res = call_function(fn, args_array);
        if(res.type == DOUBLE_TYPE) {
            printf("sin(π/2) = %.6f\n", res.value.val_double);
        }
    }

    return 0;
}

关键细节说明

  1. 参数转换:通过get_xxx_arg函数在运行时根据value_info的类型提取对应值并转换为函数期望的类型,解决了C静态类型无法动态匹配的问题。
  2. 函数指针转换:由于function_info的function union存储的是无参数的函数指针,调用时必须转换为对应参数个数和类型的函数指针(例如(double(*)(int))fn->function.f_double)。
  3. 扩展性:若需要支持更多参数个数,只需在call_function的switch中添加对应case,并实现该参数个数下的类型判断与调用逻辑即可。

内容的提问来源于stack exchange,提问作者holamynameisyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:07:35