嵌入式C开发:函数内用sizeof获取传入数组大小与外部结果不一致问题
函数内外数组计算结果不一致的本质原因
C语言存在数组形参降级规则:当数组类型被声明为函数形参时,编译器会自动将其等价转换为指向数组首元素的指针,完全丢失“数组长度”的类型信息。
对应你的运行结果完全匹配这个规则:
- 主函数中
val_array是独立的int[3]实体数组,因此sizeof(val_array)计算的是整个数组的总字节数,即3个int * 4字节 = 12字节,和输出一致 - 传入校验函数后,形参
int value_array[]在编译阶段等价于int *value_array,此时sizeof(value_array)计算的是指针本身的大小:32位环境下指针长度为4字节,也就是你看到的函数内输出Size of array:4的根源
基于这个规则,你代码中使用的NELEMS宏在函数内部计算时,实际等价于sizeof(指针)/sizeof(数组首元素)= 4/4 =1,因此循环只会遍历数组的第一个元素,不会走到值为1000的第二个元素,最终跳过数组值匹配逻辑,进入范围判断分支。而你的范围数组是{0,255},1000不在这个开区间内,才触发了“数值不合法”的错误提示。
你代码中原本写的
sizeof(value_array) >= sizeof(range_array)判断逻辑从根上就不成立:两个都是指针类型,比较指针长度没有任何业务意义,之前能走通分支仅仅是因为32位环境下所有指针长度都是4字节,属于巧合。
正确的代码调整方案
嵌入式开发场景下最稳妥、兼容性最好的修改方式,是在函数形参中显式传入数组的实际长度,补全数组降级丢失的长度信息:
- 第一步:修改校验函数的形参列表,把两个数组的长度作为独立参数传入,函数内部所有依赖
sizeof算数组大小的逻辑,全部替换为传入的长度参数#define NELEMS(x) (sizeof(x) / sizeof(x[0])) int check_val_is_valid(int32_t field_val, int value_array[], size_t value_array_len, int32_t range_array[], size_t range_array_len) { size_t size = (value_array_len >= range_array_len) ? value_array_len : range_array_len; printf("实际参与校验的数组长度: %zu\n", size); int i=0; for(i=0; i < value_array_len; i++) { printf("遍历校验值: %d\n", value_array[i]); if(value_array[i] == field_val) { return 1; } } // 增加长度边界校验,避免数组越界访问;同时将开区间判断调整为业务常用的闭区间逻辑 if (range_array_len >=2 && field_val >= range_array[0] && field_val <= range_array[1]) { return 1; } return 0; } - 第二步:修改主函数的调用逻辑,利用主函数中可以正确获取数组长度的特性,把长度值传入校验函数
int val = 1000; int val_array[] = {1, 1000, 1234}; int32_t rang_array[] = {0, 255}; // 调用时显式传入两个数组的真实长度 if (!check_val_is_valid(val, val_array, NELEMS(val_array), rang_array, NELEMS(rang_array))) { printf("The val is not valid!"); } - 额外规范提示:C语言中不推荐在函数内部对形参数组使用
sizeof来计算长度,这种写法从语法层面就永远得不到正确结果,所有跨函数传递数组的场景,必须配套传递数组的实际长度,同时增加长度合法性校验避免越界访问。
内容的提问来源于stack exchange,提问作者Marcusnh
相关产品推荐
相关产品推荐

