C++中的变长参数.doc

  1. 1、本文档共12页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
C中的变长参数

C++中的变长参数   新参与的项目中,为了使用共享内存和自定义内存池,我们自己定义了MemNew函数,且在函数内部对于非pod类型自动执行构造函数。在需要的地方调用自定义的MemNew函数。这样就带来一个问题,使用stl的类都有默认构造函数,以及复制构造函数等。但使用共享内存和内存池的类可能没有默认构造函数,而是定义了多个参数的构造函数,于是如何将参数传入MemNew函数便成了问题。 1.变长参数函数   首先回顾一下较多使用的变长参数函数,最经典的便是printf。 extern int printf(const char *format, ...);   以上是一个变长参数的函数声明。我们自己定义一个测试函数: 复制代码 #include stdarg.h #include stdio.h int testparams(int count, ...) { va_list args; va_start(args, count); for (int i = 0; i count; ++i) { int arg = va_arg(args, int); printf(arg %d = %d, i, arg); } va_end(args); return 0; } int main() { testparams(3, 10, 11, 12); return 0; } 复制代码   变长参数函数的解析,使用到三个宏va_start,va_arg 和va_end,再看va_list的定义 typedef char* va_list; 只是一个char指针。   这几个宏如何解析传入的参数呢?   函数的调用,是一个压栈,保存,跳转的过程。简单的流程描述如下: 把参数从右到左依次压入栈; 调用call指令,把下一条要执行的指令的地址作为返回地址入栈;(被调用函数执行完后会回到该地址继续执行) 当前的ebp(基址指针)入栈保存,然后把当前esp(栈顶指针)赋给ebp作为新函数栈帧的基址; 执行被调用函数,局部变量等入栈; 返回值放入eax,leave,ebp赋给esp,esp所存的地址赋给ebp;(这里可能需要拷贝临时返回对象) 从返回地址开始继续执行;(把返回地址所存的地址给eip)   由于开始的时候从右至左把参数压栈,va_start 传入最左侧的参数,往右的参数依次更早被压入栈,因此地址依次递增(栈顶地址最小)。va_arg传入当前需要获得的参数的类型,便可以利用 sizeof 计算偏移量,依次获取后面的参数值。 复制代码 1 #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) ~(sizeof(int) - 1)) 2 3 #define _ADDRESSOF(v) (const_castchar(reinterpret_castconst volatile char(v))) 4 5 #define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v))) 6 #define __crt_va_arg(ap, t) (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 7 #define __crt_va_end(ap) ((void)(ap = (va_list)0)) 8 9 #define __crt_va_start(ap, x) ((void)(__vcrt_va_start_verify_argument_typedecltype(x)(), __crt_va_start_a(ap, x))) 10 11 #define va_start __crt_va_start 12 #define va_arg __crt_va_arg 13 #define va_end __crt_va_end 复制代码   上述宏定义中,_INTSIZEOF(n) 将地址的低2位指令,做内存的4字节对齐。每次取参数时,调用__crt_va_arg(ap,t) ,返回t类型参数地址的值,同时将ap偏移到t之后。最后,调用_crt_va_end(ap)将ap置0.   变长参数的函数的使用及其原理看了宏定义是很好理解的。从上文可知,要使用变长参数函数的参数,我们必须知道传入的每个参数的类型。printf中,有format字符串中的特殊字符组合来解析后面的参数类型。但

文档评论(0)

dajuhyy + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档