C语言可变参数max函数判定-31大于6的错误排查修复
问题描述
学习va_系列可变参数宏时,编写了用于返回传入参数最大值的double max(int count, ...)函数,实际运行出现-31 > 6的错误判定结果,原代码如下:
double max(int count, ...) { double max = INT_MIN, test; int i; va_list values; va_start(values, count); for (i = 0; i < count; ++i) { test = va_arg(values, double); if (test > max) { max = test; } } va_end(values); return max; } int main() { printf("%ld", max(5, 1, 6, -31, 23, 24)); return 0; }
错误点说明
代码共有3处核心问题:
- 可变参数读取类型与传入类型不匹配:C语言可变参数没有内置类型校验,你在
main中传入的1、6、-31等参数都是int类型,常规系统下单参数占4字节栈空间,但循环中用va_arg(values, double)读取参数,double类型占8字节,读取时会跨参数拼接内存,按照IEEE754浮点数编码规则解析出完全无意义的数值,这是出现大小判定逻辑混乱的根本原因。 printf格式符与返回值类型不匹配:max函数返回值是double类型,但格式符用了对应long int类型的%ld,栈参数解析规则不匹配,会直接输出异常值。- 初始值适配问题:
max初始值设为INT_MIN(int类型最小值),如果后续传入比该值更小的double类型负数,会出现初始值大于所有合法参数的逻辑错误。
修复方法
根据实际需求二选一即可:
方案1:保留传入int整数的调用方式
修改va_arg读取类型为int,修正printf格式符,将初始值替换为double类型范围最小值,修复后代码:
#include <stdio.h> #include <stdarg.h> #include <float.h> double max(int count, ...) { // 用double类型能表示的最小值作为初始值 double max = -DBL_MAX, test; int i; va_list values; va_start(values, count); for (i = 0; i < count; ++i) { // 传入参数是int,按int类型读取 test = va_arg(values, int); if (test > max) { max = test; } } va_end(values); return max; } int main() { // double类型用%f格式符输出 printf("%f", max(5, 1, 6, -31, 23, 24)); return 0; }
方案2:保留double类型参数读取逻辑
调用max函数时传入double类型字面量,同步修正格式符和初始值:
#include <stdio.h> #include <stdarg.h> #include <float.h> double max(int count, ...) { double max = -DBL_MAX, test; int i; va_list values; va_start(values, count); for (i = 0; i < count; ++i) { test = va_arg(values, double); if (test > max) { max = test; } } va_end(values); return max; } int main() { // 传入double类型字面量,添加.0后缀标识类型 printf("%f", max(5, 1.0, 6.0, -31.0, 23.0, 24.0)); return 0; }
注意:可变参数不会做隐式类型转换校验,
va_arg指定的类型必须和实际传入参数(经过默认参数提升后的类型)严格匹配,否则会触发未定义行为。
内容的提问来源于stack exchange,提问作者Cihan Bilgihan
相关产品推荐
相关产品推荐

