zoukankan      html  css  js  c++  java
  • C 中变参函数的处理方式

    C 函数中变化的参数用‘...’ 表示。变化的参数依旧按照C函数传参的规则入栈,即从右往左依次入栈,保证参数从左往右地址依次升高。

    解析变参的主要思想是:将变参缓冲区像容纳了不同类型的数组(当然实际的数组里的变量类型不可能是不同的)一样对待。获取变参缓冲区首地址,按已知类型进行强转取值,跳过该值,取出下一个值,取完为止。

    但是这里有涉及几个问题:

    1,如何知道变参缓冲区的首地址?

    2,强转时如何知道该参数的类型?

    3,取出该值后,相应的游标应该偏移多少才能指向下一个参数首地址?

    4,何时结束解析过程,即如何知道变参的个数?

    下面依次解答上面的问题:

    首先先看一段代码(摘自微软vadefs.h):

    #elif   defined(_M_IX86)
    
    #define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
    
    #define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
    #define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
    #define _crt_va_end(ap)      ( ap = (va_list)0 )
    ...
    typedef char *  va_list;
    #ifdef  __cplusplus
    #define _ADDRESSOF(v)   ( &reinterpret_cast<const char &>(v) )
    #else
    #define _ADDRESSOF(v)   ( &(v) )
    #endif
    ...

    #define va_start _crt_va_start
    #define va_arg _crt_va_arg
    #define va_end _crt_va_end

    首先应该明确栈中数据成员均按int型字节对齐。栈中的寻址均按int型字节进行。有了这个约定我们就能解决上面4个问题中最关键的两个问题1,3。

    代码中 _INTSIZEOF(n) 计算出n所占字节是int字节数的倍数(向上取整)。

    _crt_va_start(a,v) 给出变参缓冲区的首地址,等于与第一个变参左侧第一个形参的地址加上该形参字节对齐后应占的字节数。

     _crt_va_arg(ap,t) 从宏可以看出t应该是一种类型。将ap所指地址强转成t * 然后取出该值,并将ap偏移到下一个参数首地址处。

    相信看到这里,已经知道该怎么变参了。

    至于如何知道参数个数,和参数类型,目前只能传参来解决,比如printf和scanf通过%来判断个数,通过%s,%d,%f等中s,d,f来区分类型。

  • 相关阅读:
    Leetcode 33.搜索旋转排序数组
    Leetcode 32.最长有效括号
    Leetcode 31.下一个排列
    Leetcode 30.与所有单词相关联的子串
    Leetcode 25.k个一组翻转链表
    Leetcode 24.两两交换链表中的节点
    做数据分析需要“搞”人?
    求职互联网数据分析,如何准备行业知识?
    如何利用Social Listening从社会化媒体中“提炼”有价值的信息?
    运营实操|如何利用微信后台数据优化微信运营
  • 原文地址:https://www.cnblogs.com/lc-cnblong/p/4031755.html
Copyright © 2011-2022 走看看