func_get_args()、func_get_arg()与func_num_args()

本文介绍了PHP中用于处理函数参数的三个重要函数:func_get_args()用于获取所有传入的参数并以数组形式返回;func_get_arg()通过索引获取指定参数的值,返回字符串格式;func_num_args()返回调用函数时传递的参数数量,返回整型。

func_get_args()返回当前调用函数的参数值,返回array格式;

func_get_arg(索引)返回当前函数指定索引的参数值,返回string格式;

func_num_args()返回当前调用函数的参数个数,返回int格式。




这段代码实现了一个函数注册系统,用于支持用户自定义函数,以及内置函数的管理。整体结构较为清晰,但存在几个**关键问题**: --- ## ❗存在的主要问题 --- ### ❌ 问题1:`sqrt` 直接使用标准库函数导致函数指针类型不匹配(重复问题) ```c {"sqrt", sqrt, 1} ``` - **问题描述**:`sqrt` 是 `<math.h>` 中的函数,其原型是: ```c double sqrt(double x); ``` 而你的 `FuncPtr` 类型可能是: ```c typedef double (*FuncPtr)(double*); ``` 两者参数类型不一致。 - **后果**:未定义行为,可能在某些平台上崩溃或计算错误。 --- ### ❌ 问题2:自定义函数名拷贝存在安全隐患 ```c strncpy(g_func_table[g_func_count].name, name, 19); ``` - **问题描述**: - `strncpy` 不会自动添加字符串终止符 `\0`。 - 如果 `name` 长度刚好是 19,最后一个字符会被截断,`name[19]` 没有设置为 `\0`,导致字符串不完整。 - **后果**:后续查找函数时可能出现错误或崩溃。 --- ### ❌ 问题3:函数名检查逻辑不完整 ```c if (!isalpha(name[0]) && name[0] != '_') return ERR_INVALID_CHAR; for (int i=1; name[i]; i++) { if (!isalnum(name[i]) && name[i] != '_') return ERR_INVALID_CHAR; } ``` - **问题描述**: - `name[i]` 的判断条件虽然覆盖了 `a-z`, `A-Z`, `0-9`, `_`,但没有考虑多字节字符(如 Unicode)。 - 如果 `name` 是空字符串(`""`)或 `NULL`,没有检查,会导致崩溃。 - **后果**:非法函数名未被完全拦截。 --- ### ❌ 问题4:未处理 `name` 为 `NULL` 的情况 ```c if (!isalpha(name[0]) && name[0] != '_') return ERR_INVALID_CHAR; ``` - **问题描述**:如果 `name == NULL`,访问 `name[0]` 会导致段错误(Segmentation Fault)。 --- ### ❌ 问题5:未检查 `func` 是否为 `NULL` ```c g_func_table[i].func = func; ``` - **问题描述**:如果传入的 `func` 为 `NULL`,调用时会崩溃。 --- ## ✅ 改进后的代码 ### ✅ 定义统一的函数接口(封装标准库函数) ```c typedef double (*FuncPtr)(double*); double func_sqrt(double *args) { return sqrt(args[0]); } ``` ### ✅ 使用封装后的函数进行初始化 ```c Func g_func_table[MAX_FUNCS] = { {"sin", func_sin, 1}, {"cos", func_cos, 1}, {"exp", func_exp, 1}, {"ln", func_ln, 1}, {"sqrt", func_sqrt, 1} // 使用封装后的 sqrt }; int g_func_count = 5; ``` ### ✅ 改进后的 `defineFunc` 函数 ```c ErrorCode defineFunc(const char *name, FuncPtr func, int arg_num) { if (name == NULL || func == NULL) { return ERR_INVALID_CHAR; // 参数错误 } // 检查函数名合法性 if (!isalpha(name[0]) && name[0] != '_') return ERR_INVALID_CHAR; for (int i=1; name[i]; i++) { if (!isalnum(name[i]) && name[i] != '_') return ERR_INVALID_CHAR; } // 覆盖已存在函数 for (int i=0; i<g_func_count; i++) { if (strcmp(g_func_table[i].name, name) == 0) { g_func_table[i].func = func; g_func_table[i].arg_num = arg_num; return ERR_NONE; } } // 新增函数 if (g_func_count >= MAX_FUNCS) return ERR_STACK_OVER; // 安全拷贝函数名并确保以 '\0' 结尾 strncpy(g_func_table[g_func_count].name, name, 19); g_func_table[g_func_count].name[19] = '\0'; // 确保结尾 g_func_table[g_func_count].func = func; g_func_table[g_func_count].arg_num = arg_num; g_func_count++; return ERR_NONE; } ``` --- ## ✅ 总结 | 问题 | 描述 | 解决方案 | |------|------|----------| | ❌ 函数指针不匹配 | `sqrt` 类型 `FuncPtr` 不一致 | 封装成统一接口 | | ❌ 字符串拷贝不安全 | `strncpy` 不保证 `\0` 终止符 | 手动设置 `name[19] = '\0'` | | ❌ 函数名检查不完整 | 未处理空字符串、`NULL` | 增加 `name == NULL` 检查 | | ❌ 未检查 `func` 是否为 `NULL` | 可能导致调用崩溃 | 增加 `func == NULL` 判断 | | ❌ 函数名长度未限制 | 可能溢出 | 使用固定长度数组并限制拷贝长度 | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值