引言
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。
评论