写点什么

C++ 学习 ---cstdbool 和 cstddef 源码学习分析

作者:桑榆
  • 2022 年 9 月 14 日
    广东
  • 本文字数:1862 字

    阅读完需:约 6 分钟

引言

cstdbool 是 C++对 stdbool.h 头文件的封装,里面定义了与 bool 变量相关的宏;

cstddef 是 C++对 stddef.h 头文件的封装,里面定义一些特殊类型(如 size_t),有用的宏函数(offsetof)。

平时我们都是使用这些宏或者宏函数,对于它们的原理还不是很清楚,是怎么实现这些功能的呢?接下来我们就一一来看一看源码实现。

stdbool.h

cstdbool 实现

代码参考:http://www.aospxref.com/android-13.0.0_r3/xref/external/libcxx/include/cstdbool

在 cstdbool 文件中的逻辑很简单,解除__bool_true_false_are_defined 的定义,然后将其定义为 1,标识 bool,true,false 都已经被 C++定义了。

23 #include <__config>24 25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)26 #pragma GCC system_header27 #endif28 29 #undef __bool_true_false_are_defined30 #define __bool_true_false_are_defined 131 
复制代码

C 语言的原生实现 stdbool.h

参考代码:http://www.aospxref.com/android-13.0.0_r3/xref/prebuilts/build-tools/sysroots/x86_64-linux-musl/include/stdbool.h

在该文件中,如果当前不是 C++环境,那么我们将 bool/true/false 都进行定义,同时将__bool_true_false_are_defined 定义为 1,以便后续使用。

4  #ifndef __cplusplus5  6  #define true 17  #define false 08  #define bool _Bool9  10  #endif11  12  #define __bool_true_false_are_defined 1
复制代码

总结

stdbool.h 实际上是为了解决 C/C++的兼容问题出现的。

stddef.h

代码参考:http://www.aospxref.com/android-13.0.0_r3/xref/prebuilts/build-tools/sysroots/x86_64-linux-musl/include/stddef.h

常量 NULL 的定义

从这里可以看出,实际上 NULL 有三种实现方式,0L,((void*)0)都是我们在 C 语言中常用的方式,其中的 nullptr 是 C++定义的内部类型,能够做到对很多情况的适配,不是一个单独的基本类型。

4  #if __cplusplus >= 201103L5  #define NULL nullptr6  #elif defined(__cplusplus)7  #define NULL 0L8  #else9  #define NULL ((void*)0)10  #endif
复制代码

类型的定义

其中定义了如下的类型:

x86_64 的相关实现如下:ptrdiff_t 使用 long 定义,指针减法,实际上是 64 位数的减法,long 足够表示;size_t 使用 long 表示;max_align_t 定义为拥有 long long 数据和 long double 数据的结构体;nullptr_t 定义为 nullptr 的类型。

1  #define _Addr long
59  #if defined(__NEED_ptrdiff_t) && !defined(__DEFINED_ptrdiff_t)60  typedef _Addr ptrdiff_t;61  #define __DEFINED_ptrdiff_t62  #endif
49  #if defined(__NEED_size_t) && !defined(__DEFINED_size_t)50  typedef unsigned _Addr size_t;51  #define __DEFINED_size_t52  #endif
40  #if defined(__NEED_max_align_t) && !defined(__DEFINED_max_align_t)41  typedef struct { long long __ll; long double __ld; } max_align_t;42  #define __DEFINED_max_align_t43  #endif
typedef decltype(nullptr) nullptr_t;
复制代码

offsetof 宏

offsetof (type,member)接受两个参数,类型和成员名,返回该成员的偏移地址。

听上去这个实现起来很简单,我们来看看这个精巧的宏是如何设计的。

21  #if __GNUC__ > 322  #define offsetof(type, member) __builtin_offsetof(type, member)23  #else24  #define offsetof(type, member) ((size_t)( (char *)&(((type *)0)->member) - (char *)0 ))25  #endif
复制代码

不考虑使用内建函数实现的方式,我们来看看第二种方式,这是一个比较复杂的宏,让我们来一步步拆开它,并体会其中的精妙:


((size_t)( (char *)&(((type *)0)->member) - (char *)0 ))

第一步:返回值类型强转为 size_t,规范为 byte 数,也即是偏移量;


(char *)&(((type *)0)->member) - (char *)0

第二步:char*指针转换然后做减法,得到 byte 数的差值;


第三步:((type )0)->member 这里使用了 0 指针强转为 type 指针,然后指向成员 member,此时这个变量的地址相当于 0+member 偏移,然后取地址,指针转换为 char*后做减法


这个方法的好处在于,只使用了 0 指针,没有通过其它变量的构造,很简单地找到了偏移地址,而且这个过程中做的每一步类型转换都是必要的。具体细节读者可以再品味一下,这也是我们阅读源码的收获。

发布于: 刚刚阅读数: 7
用户头像

桑榆

关注

北海虽赊,扶摇可接;东隅已逝,桑榆非晚! 2020.02.29 加入

Android手机厂商-相机软件系统工程师 爬山/徒步/Coding

评论

发布
暂无评论
C++学习---cstdbool和cstddef源码学习分析_c++_桑榆_InfoQ写作社区