最近阅读代码时看到一个很好玩的宏——ARRAYSIZE,定义在winnt.h里。
最终展开之后是这样的:
帮助01020304050607080910111213141516171819202122232425262728 // // RtlpNumberOf is a function that takes a reference to an array of N Ts. // // typedef T array_of_T[N]; // typedef array_of_T &reference_to_array_of_T; // // RtlpNumberOf returns a pointer to an array of N chars. // We could return a reference instead of a pointer but older compilers do not accept that. // // typedef char array_of_char[N]; // typedef array_of_char *pointer_to_array_of_char; // // sizeof(array_of_char) == N // sizeof(*pointer_to_array_of_char) == N // // pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T); // // We never even call RtlpNumberOf, we just take the size of dereferencing its return type. // We do not even implement RtlpNumberOf, we just decare it. // // Attempts to pass pointers instead of arrays to this macro result in compile time errors. // That is the point. // extern "C++" // templates cannot be declared to have 'C' linkage template <typename T, size_t N> char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N]; #define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A))) #define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A)
第一个点在于数组的引用
strcpy_s已经有如下这个版本的定义了
帮助12345 templateerrno_t strcpy_s( char (&strDestination)[size], const char *strSource ); // C++ only
第一个参数就是数组的引用。模板机制在这里用来帮助获取数组的大小,C里面要想把数组的大小传递给函数只有再加上一个参数来表示数组的大小。而且这种方式是类型安全的,只能传递一个char类型的数组,传递指针都会引发编译错误。
第二个点在于指向数组的指针
char (*p)[20];
char q[20];
p = &q;
此时,p是一个指针,可是它指向的类型是20个char的数组。
因此sizeof(p) == 4, sizeof(*p) == 20, p++将会让p向后移动20个字节。
明白了这2点,ARRAYSIZE宏就容易理解了。正如注释里所说RtlpNumberOf这个函数既没有定义也没有被调用过,其实下面这个模板函数也可以达到效果,但是效率就不如了。
帮助12345 template <typename T, size_t N> size_t RtlpNumberOf( UNALIGNED T (&)[N] ) { return N; }