内核为了保持最大的兼容性和代码灵活性,不可能直接对某个数据类型定义它的大小范围。但是很多时候又要用到这些最大值最小值或者该数据类型可以表示的数据范围,比如初始化一个值为最大/小值,或者检验数据是否位于某个类型的范围内。
- include/linux/kernel.h
- #define USHORT_MAX ((u16)(~0U))
- #define SHORT_MAX ((s16)(USHORT_MAX>>1))
- #define SHORT_MIN (-SHORT_MAX - 1)
- #define INT_MAX ((int)(~0U>>1))
- #define INT_MIN (-INT_MAX - 1)
- #define UINT_MAX (~0U)
- #define LONG_MAX ((long)(~0UL>>1))
- #define LONG_MIN (-LONG_MAX - 1)
- #define ULONG_MAX (~0UL)
- #define LLONG_MAX ((long long)(~0ULL>>1))
- #define LLONG_MIN (-LLONG_MAX - 1)
- #define ULLONG_MAX (~0ULL)
内核通过C语言的强制转换来实现,首先定义无符号数的最大值,比如USHORT_MAX。然后去掉符号位可以得到该类型有符号的最大值,而最小值的绝对值则比最大值的大1,所以通过对有符号的最大值取反减1,就可以得到有符号的最小值。根据这一规则可以很容易写出char类型的相关数据大小。转换的原理从下图中可以更清晰的看出来:
图 1. char型数据有无符号转换图
根据Linux对short,int,long以及long long数据类型大小的定义,可以很容易定义出char型的数据大小,示例如下:
- #include <stdio.h>
- #define UCHAR_MAX ((unsigned char)(~0U))
- #define CHAR_MAX ((char)(UCHAR_MAX >> 1))
- #define CHAR_MIN (-CHAR_MAX - 1)
- int main()
- {
- printf("UCHAR_MAX:\t%u\n", UCHAR_MAX);
- printf("CHAR_MAX:\t%d\n", CHAR_MAX);
- printf("CHAR_MIN:\t%d\n", CHAR_MIN);
- return 0;
- }
得到如下结果:
- UCHAR_MAX: 255
- CHAR_MAX: 127
- CHAR_MIN: -128
定义数据大小的方法有很多种,比如通过接下来数据对齐小节中的偏移位机制,但是这会在生成第一个数值时产生移位运算,并且在生成宽度大于32位的类型时要分别考虑,没有上面方法的效率高。一个完成相同功能的示例如下,它的思想参考数据对齐小节。
- #define CHAR_SHIFT (sizeof(char) << 3 + 1)
- #define UUCHAR_MAX ((unsigned char)((1 << CHAR_SHIFT) - 1))
- ......