由chrome源码中的arraysize想到的

在网上看到一段出自chrome的求数组长度的源代码:
  1. template<typename T, size_t N>
  2. char (&ArraySizeHelper((&array)[N]))[N];
  3. #define arraysize(array) (sizeof(ArraySizeHelper(array)))
google为什么不使用我们一般求 数组长度的方法:
  1. #define array_size(array) (sizeof(array) / sizeof(array[0]))
这是因为后者存在瑕疵:当我们传给array_size宏的不是数组名,而是指针的时候,宏array_size不会在编译的时候报错!它会得出错误的结果并且继续运行!而前者改进了后者存在的瑕疵,当我们将一个指针传给arraysize的时候,它会在编译期报错:
  1. #include <iostream>
  2. using namespace std;

  3. template<typename T, size_t N>
  4. char (&ArraySizeHelper((&array)[N]))[N];
  5. #define arraysize(array) (sizeof(ArraySizeHelper(array)))
  6. #define array_size(array) (sizeof(array) / sizeof(array[0]))

  7. int main()
  8. {
  9.     double a[200];
  10.     double *= new double[10];

  11.     std::cout << array_size(a) << std::endl;
  12.     std::cout << array_size(d) << std::endl;   // 这里输出0,因为:(4 / 8) == 0

  13.     std::cout << arraysize(d) << std::endl;    // 这里报错
  14.     std::cout << arraysize(a) << std::endl;

  15.     return 0;
  16. }
上面的代码中:array_size(d)没有报错,他会输出错误的结果:0 !!!
而代码arraysize(d)会报错: error: no matching function for call to 'ArraySizeHelper(double*&)'
这就是两者的区别所在,也是前者的高明所在!!!
 
下面我们来研究一下chrome中的代码:
  1. template<typename T, size_t N>
  2. char (&ArraySizeHelper((&array)[N]))[N];
  3. #define arraysize(array) (sizeof(ArraySizeHelper(array)))
看到代码,进过仔细的思考,会有所理解,也会有一些疑问:
它主要的思想是将数组 T array[N]转化成数组 char ArraySizeHelper[M]. 在转化前后,数组所占的内存大小没有变,所以原数组的大小等于:sizeof(ArraySizeHelper).
这里的疑问是:
array本来就是数组名,也就是数组的首地址,为什么还要在他的前面再加上取地址符&呢?这里我们先看一小段代码:
  1. int main()
  2. {
  3.     double a[200];
  4.   
  5.     printf("a:%p\n&a:%p\n", a, &a);
  6.     return 0;
  7. }
运行这段代码,我们会发现:a和&a的地址是一样的,是相等的!!!
然后,我们将上面的代码改一下:
  1. int main()
  2. {
  3.     double a[200];
  4.     printf("a:%p\n&a:%p\n", a, &a);
  5.     printf("%d\n", (== &a) );
  6.     return 0;
  7. }
编译,它报错:
error: comparison between distinct pointer types 'double*' and 'double (*)[200]' lacks a cast
从这段报错信息,我们可以得出结论:
虽然a和&a的地址值是一样的,是相等的,但是a和&a的类型却是不相同的a的类型是double *,而&a的类型是double (*)[200],a只是一个指针,而&a是一个指向数组的指针(如果可以区分开“指针数组”和“数组的指针”,那么就容易理解了。)这也就解释了:
  1. template<typename T, size_t N>
  2. char (&ArraySizeHelper((&array)[N]))[N];
这里array的前面为什么使用取地址符& ,因为这里需要的是double (*)[200],而不是double * .只有当我们传进去的是double (*)[200],模板的定义才是正确的。
所以当我们将 double *= new double[10];  传给 arraysize(d时,才会在编译的时候报错!!!
另外:代码char (&ArraySizeHelper((&array)[N]))[N];中的两个N他们的值是不一样的:第一个N是double (*)[200]中的200 , 是传进去的值, 而第二个N却是在将array传给char数组的构造函数:
 char (void *)[N]时计算出来的。
 
总结:
chrome中的ArraySizeHelper的定义利用了两点:
《1》利用了指针和数组的区别
《2》利用了char型数组的构造函数:char (void *)[N]来构造出一个新的数组ArraySizeHelper
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值