先看一下VS2005里面_countof的定义(在stdlib.h里面):
/* _countof helper */
#if !defined(_countof)
#if !defined(__cplusplus)
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
extern "C++"
{
template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
}
#endif
#endif
————————————————————华丽分割线————————————————————————
我们一步步的来对其进行解剖……
我们只看C++定义:
extern "C++"
{
template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
}
||
||
//
看得有点费力,简化一下定义如下:
template <typename T, size_t size>
char (*__countof_helper(T (&_Array)[size]))[size];
#define _countof(_Array) sizeof(*__countof_helper(_Array))
||
||
//
则对于
int Array[100];
_countof(Array)
这样的代码进行宏展开为:
sizeof(*__countof_helper(Array))
__countof_helper不知道是啥,先放这里。
回头再看看那个模板,先回顾几个知识点:
知识点一:数组指针
char (* pArrayPtr)[size];
那么 pArrayPtr 就是一个指向包含 size 个元素的 char 数组的指针(注意那个小括号的作用,它影响了C++语法解析的优先级,如果没有小括号那么就是定义了一个普通的数组,数组中的每个成员都是一个char*):
再看 char (*__countof_helper( T ( &_Array)[size] ) )[size];(为了清楚,使用了颜色进行区分)
||
||
//
看红色和绿色的部分,显然:__countof_helper(T (&_Array)[size]) 是一个函数声明,而其他部分则是该函数的返回类型,实际上就是返回一个指针数组。
而函数 __countof_helpe 参数是 T(&_Array)[size] 。
这里又有一个知识点,T(&_Array)[size] 是一个数组引用。知识点二:数组引用,这里参数使用数组引用就会保证传入的实际数组大小(size)和参数声明的数组大小是完全一致的。
||
||
//
再看回 sizeof(*__countof_helper(Array)),__countof_helper(Array)看似一个函数调用,但是实际上不会调用函数,而是直接进行编译期计算(sizeof是一个关键字,它直接在编译时计算传给它的表达式的类型的大小,没有运行时语义),此处会引发编译器模板推导,会推导出(根据int Array[100])函数原型:__countof_helper(int (&_Array)[100]) 返回值类型为:char (* pArrayPtr)[100],则sizeof(*__countof_helper(Array))里面对char (* pArrayPtr)[100]进行解引用再取sizeof的结果就是100(因为pArrayPtr就是一个指向100个元素的char数组指针,使用*解引用操作符之后就是一个100元素的char类型的数组)!!很犀利。
有几个问题:
1、微软为什么改成这样?而不用#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))这种直观的方式?有一点很重要是新方法能够进行参数类型检测了,非数组类型不能再传入_countof了,而之前是无法检查的。后来在网上看了老外的一篇文章,对这种方法的好处进行了描述,见http://blog.csdn.net/magictong/archive/2011/04/17/6329485.aspx。
2、这里面涉及到哪些知识点……?数组指针,数组引用,模板?