C语言中为何sum({1,2,3},3)调用失败?如何解决?
我们首先考虑如下定义的求和函数:
int sum(int* nums, size_t len) { int sum = 0; for(int i = 0; i < len; i++) sum += nums[i]; return sum; }
传入左值数组时,代码可以正常运行,对应的调用写法为:
int nums[] = {1,2,3}; sum(nums, 3);
但尝试直接传入花括号包裹的右值形式数组字面量调用时,代码会无法通过编译,对应写法如下:
sum({1,2,3}, 3);
目标是找到可行实现方法,让上述传入右值数组的调用方式可以正常生效。
单独的{1,2,3}是C语言的初始化列表,不属于可作为函数实参的“表达式”范畴——它没有独立的类型、没有可取的内存地址。哪怕函数形参声明为数组形式,C语言也会在编译时自动将其调整为对应类型的指针,指针类型是无法用无类型的初始化列表直接初始化的,因此这类写法在语法层面就不允许直接传入函数。
标准合规写法(C99及以上版本支持)
使用C语言的**复合字面量(compound literal)**构造带类型的临时数组对象,这是最贴近需求、没有额外副作用的实现方式。
只需要在初始化列表前加上对应数组类型的标识,生成的临时数组对象是合法的右值,会隐式退化为int*指针,满足sum函数的参数要求。改造后的合法调用写法为:
sum((int[]){1,2,3}, 3);
这种写法生成的临时数组生命周期和当前代码块绑定,sum函数的执行全程都在临时对象的有效生命周期内完成,不存在悬垂指针、内存非法访问的问题,运行结果和传入左值数组完全一致。
严格匹配原始调用写法的适配方式
如果要求完全不修改调用形式,也就是严格保留sum({1,2,3}, 3)的写法,没有纯类型层面的合法实现,因为初始化列表根本不满足函数实参的语法要求。这种场景下只能通过C预处理宏做文本替换来兼容,示例基础写法如下:
// 原sum函数保持实现不变 // 宏拦截所有调用,自动为实参补充复合字面量的类型标识 #define sum(arr, len) sum((int[])arr, len)
注意:这种宏写法会无差别替换所有sum函数的调用,对正常传入左值数组的场景会产生错误的类型转换,实际使用需要额外加判断逻辑区分左值和初始化列表的传参场景,通用性很差,优先推荐使用复合字面量的标准写法。
内容的提问来源于stack exchange,提问作者mdre。

