在c++开发中数组是我们经常使用存储结构,而于此同时“数组越界”是每个c++程序员不能不提防陷阱。

还好,我们有预定义宏_countof。

一.在visual c++开发环境下,它的定义如下:

#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

能引发兴趣的显然是__countof_helper,我们抽茧剥丝的看一下。

template <typename _CountofType, size_t _SizeOfArray>

char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];

1. 它是一个函数模板的声明,并没有函数体;

2. 它有一个参数,类型为_CountofType(&)[_SizeOfArray]的数组引用;

3. 它的返回值是一个指向数组的指针,类型为 char (*)[_SizeOfArray];

这里有几个知识点需要注意一下。

1. 数组引用

2. 数组指针

3. 模板函数

4. 数组指针的解引用

理解了函数模板__countof_helper,我们再来看看宏_countof.

#define _countof(_Array) sizeof(*__countof_helper(_Array))

可以看到,它本质是对函数__countof_helper的返回值进行了解引用之后的sizeof

而返回值是指向数组的指针,解引用之后自然就是数组本身了。

对一个char类型的数组求大小,也就是数组的大小(元素个数)了。

二.在Linux 内核中,有一个类似的求数组大小的宏ARRAY_SIZE

它的定义为:

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))

其中__must_be_array被定义为

/* &a[0] degrades to a pointer: a different type from an array */

#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))

__same_type()又被定义为

#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

BUILD_BUG_ON_ZERO是编译时期的断言宏,检查表达式e是否为0,为0编译通过且返回0;如果不为0,则编译不通过。

__builtin_types_compatible_p用来判断type1和type2是否是相同的数据类型,相同返回1,否则返回0。

一个小小的宏,有这么多东西,是不是感觉赚到了 :)

Ref:

http://www.cnblogs.com/liuzhanshan/p/6861596.html

http://www.cnblogs.com/hazir/p/static_assert_macro.html

https://msdn.microsoft.com/en-us/library/b0084kay(v=vs.100).aspx

https://stackoverflow.com/questions/8018843/macro-definition-array-size/8021113#8021113

读懂_countof,可以懂得什么的更多相关文章

  1. 如何快速读懂大型C++程序代码

    要搞清楚别人的代码,首先,你要了解代码涉及的领域知识,这是最重要的,不懂领域知识,只看代码本身,不可能搞的明白.其次,你得找各种文档:需求文档(要做什么),设计文档(怎么做的),先搞清楚你即将要阅读是 ...

  2. [Interview]读懂面试问题,在面试官面前变被动为主动

    面试是供需双方心理的较量,作为求职者来说,了解对方问题的内涵,做到“明明白白他的心”,就能变被动为主动.因此,读懂面试问题,掌握面试考官的提问的目的,有准备.有针对性地回答,对提高应聘的成功率是有很大 ...

  3. 读懂UI设计的心理学

    好文转载,版权归原作者 作为UI设计师,对待用户就像对待婴儿,知道如何通过界面设计诱导用户非常重要,这就需要了解心理学方面的知识了.今天分享一篇日本设计师的好文,结合心理学与设计,教你读懂心理学,提高 ...

  4. 一文读懂UGC:互联网上的生态秘密

    转载自近乎: UGC(User- Generated Content)用户原创生产内容,它是相对于PGC(Professionally-produced Content)专业生产内容的一种内容来源,简 ...

  5. 读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认 ...

  6. 读懂IL代码就这么简单(二)

    一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...

  7. 读懂IL代码就这么简单 (一)

    一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...

  8. 一张图读懂https加密协议

    搭建CA服务器和iis启用https:http://blog.csdn.net/dier4836/article/details/7719532 一张图读懂https加密协议 https是一种加密传输 ...

  9. Gradle学习系列之三——读懂Gradle语法

    在本系列的上篇文章中,我们讲到了创建Task的多种方法,在本篇文章中,我们将学习如何读懂Gradle. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...

随机推荐

  1. asp.net core 2.0+sqlsugar搭建个人网站系列(0)

    一些废话 马上就要过年了,回顾这一年最大的收获就是技术有了很大的提升,其他的方面没有什么改变,现在还是单身小屌丝一枚. 这一年来学习的主要重点就是asp.net core,中间也使用 core+EF做 ...

  2. Handwritten Parsers & Lexers in Go (翻译)

    用go实现Parsers & Lexers 在当今网络应用和REST API的时代,编写解析器似乎是一种垂死的艺术.你可能会认为编写解析器是一个复杂的工作,只保留给编程语言设计师,但我想消除这 ...

  3. [E::hts_idx_push] NO_COOR reads not in a single block at the end 10 -1

    在分析转录组数据时,用bowtie2比对生成的bam文件,下一步call peak使用m6Aviewer,需要bam文件的index文件.所以我直接敲命令 samtools index xx.bam ...

  4. MongoDB数据库详解

    第1章 数据库管理系统 1.1 前言 01.数据的定义:文字.图像.地理位置信息(坐标.经纬度)等 02.数据库管理系统的定义:建立.存取和管理数据,保证数据安全和完整性的软件 03.常见的数据库管理 ...

  5. 区分javascript中的toString(),toLocaleString(),valueOf()方法

    首先我们随意创建一个对象,这很简单,打开FF浏览器的Firebug切换到控制台或者打开webkit浏览器的审查元素功能. 输入以下内容: var obj1=[1,2,3,4,5] var obj2=[ ...

  6. 如何高逼格读取Web.config中的AppSettings

    http://edi.wang/post/2015/4/22/how-to-read-webconfig-appsettings-with-bigiblity 先插句题外话,下版本的ASP.NET貌似 ...

  7. Django ORM详解

    ORM:(在django中,根据代码中的类自动生成数据库的表也叫--code first) ORM:Object Relational Mapping(关系对象映射) 我们写的类表示数据库中的表 我们 ...

  8. 微信小程序之使用本地接口开发

    本文主要讲解如何使用本地接口进行开发,很多人都会遇到这个问题,特别是小程序上线后. 一.解决思路 在小程序开发工具设置网络代理,然后再通过Charles设置代理,将https域名转为本地接口进行访问. ...

  9. Sql 关于 查俩个表 第二个表用到第一个表的某一个数据

    今天在写程序的时候遇到一个问题  有一个这个需求 select top 1 Name,[Address] from UserInfo;select * from shoppingAddress whe ...

  10. A session had already been started – ignoring session_start() 怎么办?

    php警告提示A session had already been started – ignoring session_start() 解决方案 访问log日志发现有个这样的警告 主要是在TP框架中 ...