写点什么

C++ 学习 ------cstdint 头文件的源码学习

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

    阅读完需:约 15 分钟

引言

cstdint 头文件是 C++对 stdint 头文件的封装,这个头文件定义了一系列特定长度的类型别名,一系列值的上下限,以及一系列类型转换的宏。我们一起来看看它的内部实现。

代码参考: http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/include/stdint.h

stdint.h 的源码实现

类型别名定义

常见的基础整型有 char、short、int、long、long long,再加上 unsigned 和 signed 的修饰,就有多种不同的组合,特别是在 32 位机器和 64 位机器上各种数据类型所占用的位数有不同。

C 语言中只规定了基本的约束:short 和 int 型至少为 16 位,long 型至少为 32 位,并且 short 型长度不能超过 int 型,而 int 型不能超过 long 型。

数据类型占内存的位数实际上与操作系统的位数和编译器(不同编译器支持的位数可能有所不同)都有关 ,具体某种数据类型占字节数得编译器根据操作系统位数两者之间进行协调好后分配内存大小。

stdint.h 文件中就考虑到了这一点,定义了许多与机器位数无关的类型,一定是固定的位数。

内部类型:__intx_t、__uintx_t(x=8,16,32,64),__intptr_t、__uintptr_t

36  typedef signed char __int8_t;37  typedef unsigned char __uint8_t;38  typedef short __int16_t;39  typedef unsigned short __uint16_t;40  typedef int __int32_t;41  typedef unsigned int __uint32_t;42  #if defined(__LP64__)43  typedef long __int64_t;44  typedef unsigned long __uint64_t;45  #else46  typedef long long __int64_t;47  typedef unsigned long long __uint64_t;48  #endif49  50  #if defined(__LP64__)51  typedef long __intptr_t;52  typedef unsigned long __uintptr_t;53  #else54  typedef int __intptr_t;55  typedef unsigned int __uintptr_t;56  #endif
复制代码

定义内部类型,说明一下__LP64__是 64 位机器会定义的一个宏,可以用它来判断机器类型,通过上面的别名设置,我们也可以推测出,在 32 位机器上,long long 占用 64 位,int 和 long 占用 32 位,short 占用 16 位,char 占用 8 位。

基础类型定义

这里是对上面内部类型的封装,C 语言中一般双下划线开头的都是内部类型,不建议直接在代码中使用。8/16/32/64/ptr 的封装没有什么变化,这里还额外定义了

  • uint_leastx_t/int_leastx_t(x=8,16,32,64),该类型说明不存在占位大小较小且至少具有指定宽度的其他整数类型

  • uint_fastx_t/int_fastx_t(x=8,16,32,64),该类型至少与具有指定宽度的任何其他整数类型一样快。

  • uintmax_t/intmax_t,占位最大的 size

即这样的定义完全与机器位数无关,给定的类型定义一定拥有准确的位数,不会出现迁移的异常,正常的使用过程中也建议使用这样的类型定义,避免在 32 位机器与 64 位机器上表现不一致。

58  typedef __int8_t      int8_t;59  typedef __uint8_t     uint8_t;60  61  typedef __int16_t     int16_t;62  typedef __uint16_t    uint16_t;63  64  typedef __int32_t     int32_t;65  typedef __uint32_t    uint32_t;66  67  typedef __int64_t     int64_t;68  typedef __uint64_t    uint64_t;69  70  typedef __intptr_t    intptr_t;71  typedef __uintptr_t   uintptr_t;72  73  typedef int8_t        int_least8_t;74  typedef uint8_t       uint_least8_t;75  76  typedef int16_t       int_least16_t;77  typedef uint16_t      uint_least16_t;78  79  typedef int32_t       int_least32_t;80  typedef uint32_t      uint_least32_t;81  82  typedef int64_t       int_least64_t;83  typedef uint64_t      uint_least64_t;84  85  typedef int8_t        int_fast8_t;86  typedef uint8_t       uint_fast8_t;87  88  typedef int64_t       int_fast64_t;89  typedef uint64_t      uint_fast64_t;90  91  #if defined(__LP64__)92  typedef int64_t       int_fast16_t;93  typedef uint64_t      uint_fast16_t;94  typedef int64_t       int_fast32_t;95  typedef uint64_t      uint_fast32_t;96  #else97  typedef int32_t       int_fast16_t;98  typedef uint32_t      uint_fast16_t;99  typedef int32_t       int_fast32_t;100  typedef uint32_t      uint_fast32_t;101  #endif102  103  typedef uint64_t      uintmax_t;104  typedef int64_t       intmax_t;
复制代码

常见整型的上下限

这里事先定义了如下整形的上下限


注意:这里用到了一些宏定义,我们在后面一节里面会说明它的含义

154  #define INT8_MIN         (-128)155  #define INT8_MAX         (127)156  #define INT_LEAST8_MIN   INT8_MIN157  #define INT_LEAST8_MAX   INT8_MAX158  #define INT_FAST8_MIN    INT8_MIN159  #define INT_FAST8_MAX    INT8_MAX160  161  #define UINT8_MAX        (255)162  #define UINT_LEAST8_MAX  UINT8_MAX163  #define UINT_FAST8_MAX   UINT8_MAX164  165  #define INT16_MIN        (-32768)166  #define INT16_MAX        (32767)167  #define INT_LEAST16_MIN  INT16_MIN168  #define INT_LEAST16_MAX  INT16_MAX169  #define INT_FAST16_MIN   INT32_MIN170  #define INT_FAST16_MAX   INT32_MAX171  172  #define UINT16_MAX       (65535)173  #define UINT_LEAST16_MAX UINT16_MAX174  #define UINT_FAST16_MAX  UINT32_MAX175  176  #define INT32_MIN        (-2147483647-1)177  #define INT32_MAX        (2147483647)178  #define INT_LEAST32_MIN  INT32_MIN179  #define INT_LEAST32_MAX  INT32_MAX180  #define INT_FAST32_MIN   INT32_MIN181  #define INT_FAST32_MAX   INT32_MAX182  183  #define UINT32_MAX       (4294967295U)184  #define UINT_LEAST32_MAX UINT32_MAX185  #define UINT_FAST32_MAX  UINT32_MAX186  187  #define INT64_MIN        (INT64_C(-9223372036854775807)-1)188  #define INT64_MAX        (INT64_C(9223372036854775807))189  #define INT_LEAST64_MIN  INT64_MIN190  #define INT_LEAST64_MAX  INT64_MAX191  #define INT_FAST64_MIN   INT64_MIN192  #define INT_FAST64_MAX   INT64_MAX193  #define UINT64_MAX       (UINT64_C(18446744073709551615))194  195  #define UINT_LEAST64_MAX UINT64_MAX196  #define UINT_FAST64_MAX  UINT64_MAX197  198  #define INTMAX_MIN       INT64_MIN199  #define INTMAX_MAX       INT64_MAX200  #define UINTMAX_MAX      UINT64_MAX201  202  #define SIG_ATOMIC_MAX   INT32_MAX203  #define SIG_ATOMIC_MIN   INT32_MIN204  205  #if defined(__WINT_UNSIGNED__)206  #  define WINT_MAX       UINT32_MAX207  #  define WINT_MIN       0208  #else209  #  define WINT_MAX       INT32_MAX210  #  define WINT_MIN       INT32_MIN211  #endif212  213  #if defined(__LP64__)214  #  define INTPTR_MIN     INT64_MIN215  #  define INTPTR_MAX     INT64_MAX216  #  define UINTPTR_MAX    UINT64_MAX217  #  define PTRDIFF_MIN    INT64_MIN218  #  define PTRDIFF_MAX    INT64_MAX219  #  define SIZE_MAX       UINT64_MAX220  #else221  #  define INTPTR_MIN     INT32_MIN222  #  define INTPTR_MAX     INT32_MAX223  #  define UINTPTR_MAX    UINT32_MAX224  #  define PTRDIFF_MIN    INT32_MIN225  #  define PTRDIFF_MAX    INT32_MAX226  #  define SIZE_MAX       UINT32_MAX227  #endif
复制代码

与之前不同,这里的 fast 值和 least 值的 max 和 min 定义大部分与对应的基础值一样,不一样的是:

#define INT_FAST16_MIN   INT32_MIN#define INT_FAST16_MAX   INT32_MAX
复制代码

定义为 INT32_MIN 和 INT32_MAX 同时,其它的一些 size,如 SIG_ATOMIC_MAX(原子量),WINT_MAX(根据是否有符号进行区分),PTRDIFF_MAX(指针运算差值)SIZE_MAX(size_t 的取值)

类型转换宏

实际上是运用了字面值常量的前后缀来生成宏:

  • u 或 U,最小匹配 unsigned

  • l 或 L,最小匹配 long

  • ll 或 LL,最小匹配 long long

106  /* Keep the kernel from trying to define these types... */107  #define __BIT_TYPES_DEFINED__108  109  #define INT8_C(c)         c110  #define INT_LEAST8_C(c)   INT8_C(c)111  #define INT_FAST8_C(c)    INT8_C(c)112  113  #define UINT8_C(c)        c114  #define UINT_LEAST8_C(c)  UINT8_C(c)115  #define UINT_FAST8_C(c)   UINT8_C(c)116  117  #define INT16_C(c)        c118  #define INT_LEAST16_C(c)  INT16_C(c)119  #define INT_FAST16_C(c)   INT32_C(c)120  121  #define UINT16_C(c)       c122  #define UINT_LEAST16_C(c) UINT16_C(c)123  #define UINT_FAST16_C(c)  UINT32_C(c)124  #define INT32_C(c)        c125  #define INT_LEAST32_C(c)  INT32_C(c)126  #define INT_FAST32_C(c)   INT32_C(c)127  128  #define UINT32_C(c)       c ## U129  #define UINT_LEAST32_C(c) UINT32_C(c)130  #define UINT_FAST32_C(c)  UINT32_C(c)131  #define INT_LEAST64_C(c)  INT64_C(c)132  #define INT_FAST64_C(c)   INT64_C(c)133  134  #define UINT_LEAST64_C(c) UINT64_C(c)135  #define UINT_FAST64_C(c)  UINT64_C(c)136  137  #define INTMAX_C(c)       INT64_C(c)138  #define UINTMAX_C(c)      UINT64_C(c)139  140  #if defined(__LP64__)141  #  define INT64_C(c)      c ## L142  #  define UINT64_C(c)     c ## UL143  #  define INTPTR_C(c)     INT64_C(c)144  #  define UINTPTR_C(c)    UINT64_C(c)145  #  define PTRDIFF_C(c)    INT64_C(c)146  #else147  #  define INT64_C(c)      c ## LL148  #  define UINT64_C(c)     c ## ULL149  #  define INTPTR_C(c)     INT32_C(c)150  #  define UINTPTR_C(c)    UINT32_C(c)151  #  define PTRDIFF_C(c)    INT32_C(c)152  #endif
复制代码

所以,上面的匹配中,针对 32 位机器的无符号 64 位表示为:# define UINT64_C(c) c ## ULL

"##"在宏定义中代表将前后以字符相连,即一个数字将表示为 cULL,即该字面值为 unsigned long long 类型

回到之前我们定义上下限的位置,UINT64_C(18446744073709551615)在编译时就被表示为 18446744073709551615ULL。

总结

stdint.h 头文件中定义是为了兼容 32 位和 64 位机器,保证使用对应的定义能够获取对应位数的变量,平时我们在编程时,也需要多加考虑程序在多个平台之间的可移植性,尽量使用与平台无关的变量定义,如使用 int32_t 代替 int。

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

桑榆

关注

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

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

评论

发布
暂无评论
C++学习------cstdint头文件的源码学习_c++_桑榆_InfoQ写作社区