int * 类型的实参与 int 类型的形参不兼容_C++|可变参数函数的实现及其不安全性...

本文探讨了可变参数函数的实现原理,重点讲解了不同类型的可变参数处理方式(整数计数、哨兵值和字符串解析),以及它们在实际应用中的优势与潜在风险,包括缺乏类型检查和依赖于额外参数判断参数数量。通过实例演示和汇编代码解析,揭示了可变参数的局限性和安全性问题。
摘要由CSDN通过智能技术生成

可变参数函数头的一般格式:

return_type function_name(argument_list, ...)

最右边是省略号“...”,省略号“...”的左边必须至少有一形参,必须由靠近省略号“...”的形参来识别省略号“...”表示的形参数量,可以是以下类型:

a 表示长度的int类型;

b 表示哨兵类型的int类型;

c 表示参数类型及数量的字符串,通过解析字符串的字符来解析以后的参数数量及类型;

1 传递一个表示长度的int类型参数

#include #include  // needed to use ellipsis // The ellipsis must be the last parameter// count is how many additional arguments we're passingdouble findAverage(int count, ...){ double sum = 0;  // We access the ellipsis through a va_list, so let's declare one va_list list;  // We initialize the va_list using va_start. The first parameter is // the list to initialize. The second parameter is the last non-ellipsis // parameter. va_start(list, count);  // Loop through all the ellipsis arguments for (int arg=0; arg < count; ++arg) // We use va_arg to get parameters out of our ellipsis // The first parameter is the va_list we're using // The second parameter is the type of the parameter sum += va_arg(list, int);  // Cleanup the va_list when we're done. va_end(list);  return sum / count;} int main(){ std::cout << findAverage(6, 1, 2, 3, 4, 5, 6) << ''; // 3.5 std::cout << findAverage(6, 1.0, 2, 3, 4, 5, 6) << ''; // 1.79766e+008system("pause");return 0;}

在头文件stdarg定义了四个宏:va_list, va_arg, va_start, and va_end,可结合上面的实例并结合栈表示如下:

618791895bcc0744c322579278386014.png

看汇编代码:

70bcfe16f0c5b1ccd7afd4941fe689fd.png

对于findAverage(6, 1.0, 2, 3, 4, 5, 6),并没有得到我们期望的结果,这就是因为其无法完成数据类型的检查,自然也无法做隐式数据类型转换,看汇编代码:

4071085b9d372faf836aa5fceb093120.png

在2和6之间压入了3FF00000h和0

00401630 push 2

00401632 push 3FF00000h

00401637 push 0

00401639 push 6

按照IEEE754浮点数算数标准,double浮点数字长64位,一位是符号位,指数长度11,指数偏移量1023,尾数长度52;1.0指数位是0,偏移1023就是10个1,其它位都是0:

0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

分成两个32位,后面的32位是0,前面的二进制位用16进制表示成整数就是:3FF00000h,除以6后就得到1.79766e+008。

1f09d1bf0a40e43f93a4dca597134c2c.png

以上就是可变参数的优势和不安全性。

因为是用宏实现的,所以没有类型检查,且参数数量需要通过其它参数去判断。

2 传递一个哨兵值参数

#include #include  // needed to use ellipsis // The ellipsis must be the last parameterdouble findAverage(int first, ...){// We have to deal with the first number speciallydouble sum = first; // We access the ellipsis through a va_list, so let's declare oneva_list list; // We initialize the va_list using va_start. The first parameter is// the list to initialize. The second parameter is the last non-ellipsis// parameter.va_start(list, first); int count = 1;// Loop indefinitelywhile (1){// We use va_arg to get parameters out of our ellipsis// The first parameter is the va_list we're using// The second parameter is the type of the parameterint arg = va_arg(list, int); // If this parameter is our sentinel value, stop loopingif (arg == -1)break; sum += arg;count++;} // Cleanup the va_list when we're done.va_end(list); return sum / count;} int main(){std::cout << findAverage(1, 2, 3, 4, 5, -1) << '';std::cout << findAverage(1, 2, 3, 4, 5, 6, -1) << '';}

3 传递一个字符串参数

#include #include #include  // needed to use ellipsis // The ellipsis must be the last parameterdouble findAverage(std::string decoder, ...){double sum = 0; // We access the ellipsis through a va_list, so let's declare oneva_list list; // We initialize the va_list using va_start. The first parameter is// the list to initialize. The second parameter is the last non-ellipsis// parameter.va_start(list, decoder); int count = 0;// Loop indefinitelywhile (1){char codetype = decoder[count];switch (codetype){default:case '0':// Cleanup the va_list when we're done.va_end(list);return sum / count; case 'i':sum += va_arg(list, int);count++;break; case 'd':sum += va_arg(list, double);count++;break;}}} int main(){std::cout << findAverage("iiiii
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值