美文网首页
ARRAYSIZE宏讲解

ARRAYSIZE宏讲解

作者: 于天佐 | 来源:发表于2018-07-06 11:50 被阅读0次

    ARRAYSIZE宏

        不同的C++实现有很多的库中都有一个计算数组长度的宏,名字大致都叫ARRAYSIZE,如VS中就定义了这个宏,它的使用很简单,len = ARRAYSIZE(a),只要传入的a是一个数组就能计算出这个数组的长度。实际上计算数组的常用套路是这样的

    #define ARR_SIZE(A) (sizeof(A)/sizeof(A[0]))
    

        上面这个计算方法有很多问题,如果传入的A是指针那就不可能计算出来正确的数组长度了,而现实中数组退化成指针的情况非常多。所以综合考虑下结合C++的特性就出现了ARRAYSIZE这个新的C++下使用的全新宏。它克服了上面说的传统arraysize的问题,那么直接看一下它的实现:

    template<typename T, unsigned int N>
    char (&array_size_fake_func(T(&)[N]))[N];
    
    #define MYARRAYSIZE(A) sizeof(array_size_fake_func(A))
    

        上面的语法极难看懂,因为平时几乎用不到,那么我们来分析一下这段简单的代码。它的核心实际上是上面的模板函数的一个声明,抛开模板,这个函数的参数和返回值都是T类型数组(数组长度N)的引用,很不常见吧,这里容易忽视的一个语法是c/c++是不支持函数返回数组的(java可以),所以这里返回数组的引用(或指针),而数组的引用语法本身很少用,并且写法比较怪。弄清楚了函数的结构,我们先看一下数组引用的使用

        //返回一个数组引用的函数,参数也是一个数组引用
        static int (&ret_arr_ref(int(&ref)[6]))[6]
        {
            return ref;
        }
        int a[6] = {0};
        int (&arf)[6] = a;
        arf[0] = 1;
        int (&arf2)[6] = ret_arr_ref(a);
        //arf 和 arf2 均是指向数组a的数组引用
    

        以上代码比较清晰的解释了数组引用如何用,那么回到刚才的模板函数,通过传入参数的推导(如果是一个数组类型变量),编译器就可以推导出T和N,这里我们更关心N的值,我们再通过拿到返回值char[N]的引用ref,求它的长度len = sizeof(ref),显然len就是N,通过上面的推导,就可以把N的值传递出来了。这里的好处是,如果传递给函数的参数不是数组,而是退化的指针,那么编译会报错,因为无法推导出N,这就有效的防止了数组退化成指针的问题,从编译层面彻底杜绝了这种情况的发生,从而保证计算数组长度的准确性。
        在看一下宏#define MYARRAYSIZE(A) sizeof(array_size_fake_func(A)),其中sizeof(array_size_fake_func(A)),sizeof是编译期行为,所以这里函数并不产生调用,只是产生函数返回值类型,这个函数甚至不需要调用就能推导出N,所以这个宏没有额外的运行期损耗,所以这就是它的优势,没有类型不明确造成的错误(数组退化指针),没有运行期效率损失。
        这个神奇的宏实现背后隐藏着很多故事,通过层层分析我们大致了解了它背后的实现原理和优势,以后碰到计算数组长度的场景尽量用这个宏吧,安全又快捷。

    相关文章

      网友评论

          本文标题:ARRAYSIZE宏讲解

          本文链接:https://www.haomeiwen.com/subject/qxpvuftx.html