C语言中int数组传入期望float数组的函数为何未隐式转换且读出0?
问题解答:int数组传入期望float数组的函数为何读出0值?
问题背景
我编写了一个计算数组总和并返回给main(),再由main()计算平均值的程序。SumOfArray()函数期望接收float类型数组,但我传入的是int类型数组,原本预期整数会隐式转换为float类型(如35转为35.0),但实际读出的值都是0。查到的简短解释是该行为属于未定义行为,因为此处并非int转为float,而是int*转为float*。但我疑惑的是:
- 数组在
main()和SumOfArray()中的地址一致,且我的机器上int和float的大小均为4字节,为何函数读出的是0而非实际整数? - ISO C标准中是否有相关规定?
我使用gcc编译器、Code::Blocks IDE,编译目标为x86_64架构,也在Debian系统上做了测试。
代码与输出
源代码
#include<stdio.h> float SumOfArray(const float array[], unsigned int size) { float sum = -1.0; if(size != 0 && array != 0) { sum = 0; for(int i = 0; i < size; i++) { sum += array[i]; printf("sum in sum of array is %f\n", sum); printf("array[%d] is %f\n", i, array[i]); } } return sum; } int main() { int gradesI[] = {35, 56, 88, 23, 45, 99}; unsigned int sizeI = sizeof(gradesI)/sizeof(int); float sumI = SumOfArray(gradesI, sizeI); printf("the sum of is %f\n", sumI); float average = sumI/sizeI; printf("the average is %f\n", average); return 0; }
运行输出
sum in sum of array is 0.000000 array[0] is 0.000000 sum in sum of array is 0.000000 array[1] is 0.000000 sum in sum of array is 0.000000 array[2] is 0.000000 sum in sum of array is 0.000000 array[3] is 0.000000 sum in sum of array is 0.000000 array[4] is 0.000000 sum in sum of array is 0.000000 array[5] is 0.000000 the sum of is 0.000000 the average is 0.000000
原因分析
为何读出的是0?
你将int*(数组退化为指针)隐式转换成了float*,这是违规操作。SumOfArray()函数会按照float的二进制格式去解析原本是int的二进制数据,两者的编码规则完全不同:
以第一个元素35为例,它的32位int二进制是:00000000 00000000 00000000 00100011
而32位float的格式是:1位符号位 + 8位指数位 + 23位尾数位。把上面的二进制当成float解析:
- 符号位为0(表示正数)
- 指数位是
00000000,对应float的偏移指数规则,实际指数为0 - 127 = -127,属于非规格化数范围 - 尾数位是
0000000000100011,非规格化数的实际值计算公式为:(尾数位 / 2^23) * 2^(-126)
这个值约为5.3e-38,是一个极小的数,用%f格式化输出时(默认保留6位小数)会被舍入为0.000000。其他int元素的二进制解析成float后也都是类似的极小值,因此输出全为0。
ISO C标准的相关规定
根据ISO C标准(如C17版本):
- 在§6.3.2.3 指针部分明确:不同类型的指针(除
void*与其他指针的转换外)之间的转换属于未定义行为,除非是指向兼容类型的指针,或是指向带有不同限定符的兼容类型(比如const float*和float*)。 - 你将
int[]传给期望const float[]的函数时,数组退化为int*,随后被隐式转换为float*,这属于不兼容指针类型的转换,标准明确这种行为是未定义的——编译器可以任意处理,包括输出0、程序崩溃、甚至看似正常的结果,完全取决于编译器实现。
解决方案
有两种合法的修正方式:
- 转换数组类型后传入:先将int数组的每个元素转换成float,存入新的float数组再传入函数:
int gradesI[] = {35, 56, 88, 23, 45, 99}; unsigned int sizeI = sizeof(gradesI)/sizeof(int); float gradesF[sizeI]; for(int i = 0; i < sizeI; i++){ gradesF[i] = gradesI[i]; // 此处是合法的int到float的隐式转换 } float sumI = SumOfArray(gradesF, sizeI);
- 修改函数适配int数组:编写专门处理int数组的求和函数,或者将函数改造成通用型(比如结合
void*和类型参数,但需要额外的类型判断逻辑),最简单的是新增SumOfIntArray函数,与原SumOfArray函数区分开。
内容的提问来源于stack exchange,提问作者Jane
相关产品推荐
相关产品推荐

