• ArraySizeHelper解析


    ArraySizeHelper解析

      以下代码用于获取一个数组的元素个数,例如 int table[100],以下宏返回100。

    template <typename T, size_t N> 
    char (&ArraySizeHelper(const T (&array)[N]))[N]; 
    #define arraysize(array) (sizeof(ArraySizeHelper(array)))
    

     [要点

     1、数组的引用

      T (&)[N] (注意:有个括号)。比如:
      int a[5] = {0};
      int (&ra)[5] = a; 这里ra就是一个对数组a的引用,其这个数组的大小也是5;

     2、返回值为数组引用的函数

      T (& Fun( param_list ) )[N];
      Fun是一个函数,其返回值类型是 T (&)[N];

     3、sizeof()在编译期完成,与运行时无关

      sizeof是C/C++语言中的keyword,不是函数。对其参数里的表达式是不会在执行期去执行的,而只是在编译期去推算整个表达式的最后的类型信息。
      比如: int a = 1; sizeof(a++); cout << a;   // a还是1. 不会是2;
      因为是在编译期完成,编译器只需要类型信息,不需要函数的实现体。所以就可以不用提供定义体。
      下面这个例子可能更能说明这个问题。
      int Fun(); // only declare it without definition
      sizeof( Fun() );  // 这里Fun()函数不会在运行的时候被执行,仅仅是在编译时,编译器需要知道的是:Fun()函数返回值的类型是什么。

     4、模板自动推导在编译期完成

      模板推导是由编译器在编译期(compile time)完成的,而不是在执行期(run time)完成的。

      这个是理解的关键之一。不涉及内存布局分配的问题。编译期间,编译器只关心声明信息(也就是声明式里面所带的类型信息)。模板推导会自动推导模板参数的各种信息(类型,传递过来的数值等)。以下是一个例子:
      template<int x, int y>
      struct sum_
      {
        enum { value = x + y };
      };
      int sum = sum_<3, 4>::value; // sum的值在编译期间就已经确定下来了,不是在执行期间由CPU运算得到。
      这个例子里的模板,仅仅只有数值的传递,没有包含类型。这个可能大家很少见到的。但是模板是支持的。

      例子二:
      template< typename T, size_t N>
      void Fun( T (&)[N] );

      这个模板里既有类型T,又有数值N;模板推导时,是根据Fun的实参来推导得到的。比如:
      int a[5];
      Fun(a); // 编译器经过推导就知道,T=int,N=5。注意这里的N能得到5,是因为Fun的参数声明决定的。这里Fun的参数是:数组引

       5、sizeof(一个指针)和sizeof(一个数组)有很大区别
      
      int a[5];

      int *p = a;
      int (*pa)[5] = &a;


      // p和pa都是指针,但是指针的类型不同:p的类型是int*;pa的类型是int(*)[5]。


      sizeof(p)       // = 4;
      sizeof(a)       // = 20 = 5*sizeof(int)
      sizeof(*p)     // = sizeof(int) = 4;
      sizeof(pa)    // = 4;
      sizeof(*pa)  // = sizeof(a) = 20;

     6、跨函数类型信息丢失

      C/C++对于数组和指针是明确区分其类型的。数组的信息包括(类型+大小),而指针则没有大小信息。
      在这里附带要说一下,数组经过函数参数传递后,数组的大小信息就丢失了。比如:
      void Fun( int a[5] )
      {   
          int n = sizeof(a);  // n为4,相对于就是sizeof(int*).因为编译器只传递过来了数组的地址,大小信息没有了。
      }


      所以,上面Fun的参数声明里面的数组的具体数字是被忽略掉的。其等价声明式可以是:
      void Fun( int a[10] );
      void Fun( int a[] );
      void Fun( int *a );


      为了需要把大小信息传递到函数里面去,需要额外加一个参数来表示大小信息,这个大小信息需要调用者来提供,并且有调用者来保证大小信息的正确性。
      void Fun( int a[], int size );

     

      

  • 相关阅读:
    ES6 Set
    JavaScript 之 对象属性的特性 和defineProperty方法
    ES6 ... 展开&收集运算符
    ES6 箭头函数
    ES6 解构 destructuring
    canvas之事件交互效果isPointPath
    跨域及JSONP原理
    P03 显示隐藏
    最长公共子序列
    P02 CSS样式
  • 原文地址:https://www.cnblogs.com/tekkaman/p/3268518.html
Copyright © 2020-2023  润新知