本文主要涉及到的库文件位于/usr/include/bits目录下,文件包括wordsize.h,types.h,typesizes.h 等文件。
wordsize.h中主要定义了当前机器的字大小。内容如下:
...
#define __WORDSIZE 32
...
这里的宏应该是安装系统的时候,确定的机器字的大小,然后才生成对应的宏。这个宏会在types.h中作为判定条件,从而定义相应数据类型。我们可以看下types.h文件有如下内容:
99 #define __S16_TYPE short int
100 #define __U16_TYPE unsigned short int
101 #define __S32_TYPE int
102 #define __U32_TYPE unsigned int
103 #define __SLONGWORD_TYPE long int
104 #define __ULONGWORD_TYPE unsigned long int
//以上类型定义与机器字长度无关
105 #if __WORDSIZE == 32
106 # define __SQUAD_TYPE __quad_t
107 # define __UQUAD_TYPE __u_quad_t
108 # define __SWORD_TYPE int
109 # define __UWORD_TYPE unsigned int
110 # define __SLONG32_TYPE long int
111 # define __ULONG32_TYPE unsigned long int
112 # define __S64_TYPE __quad_t
113 # define __U64_TYPE __u_quad_t
114 /* We want __extension__ before typedef's that use nonstandard base types
115 such as `long long' in C89 mode. */
116 # define __STD_TYPE __extension__ typedef //如果机器为32位,我们需要使用扩展数据类型定义宏
117 #elif __WORDSIZE == 64
118 # define __SQUAD_TYPE long int
119 # define __UQUAD_TYPE unsigned long int
120 # define __SWORD_TYPE long int
121 # define __UWORD_TYPE unsigned long int
122 # define __SLONG32_TYPE int
123 # define __ULONG32_TYPE unsigned int
124 # define __S64_TYPE long int
125 # define __U64_TYPE unsigned long int
126 /* No need to mark the typedef with __extension__. */
127 # define __STD_TYPE typedef
//如果机器为64位,我们不需要在typedef前加扩展宏 __extension__,后面的__STD_TYPE 即表示typedef
128 #else
129 # error
130 #endif
上面的# define __SQUAD_TYPE __quad_t表示当机器为32位,但是又要表示64位数据时,我们可以通过如下方法定义:
/* quad_t is also 64 bits. */
52 #if __WORDSIZE == 64
53 typedef long int __quad_t;
54 typedef unsigned long int __u_quad_t;
55 #elif defined __GLIBC_HAVE_LONG_LONG
56 __extension__ typedef long long int __quad_t;
57 __extension__ typedef unsigned long long int __u_quad_t;
58 #else //32位机器
59 typedef struct
60 {
61 long __val[2];
62 } __quad_t;
63 typedef struct
64 {
65 __u_long __val[2];
66 } __u_quad_t;
67 #endif
131 #include <bits/typesizes.h> /* Defines __*_T_TYPE macros. */
//将typesizes.h包含进来,因为里面通过定义了所有的 __*_T_TYPE宏,而这些宏都是下面的类型定义的基础
135 __STD_TYPE __UID_T_TYPE __uid_t; /* Type of user identifications. */
136 __STD_TYPE __GID_T_TYPE __gid_t; /* Type of group identifications. */
143 __STD_TYPE __PID_T_TYPE __pid_t; /* Type of process identifications. */
155 __STD_TYPE __KEY_T_TYPE __key_t; /* Type of an IPC key. */
注意这里的__STD_TYPE = typedef 不再是宏定义,而是类型定义
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们可以查看typesizes.h文件,内容如下:
1 /* bits/typesizes.h -- underlying types for *_t. Generic version.
这个文件用来定义类似于*_t的基本类型(underlying type)
.....
2 */
19
20 #ifndef _BITS_TYPES_H
21 # error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead."
22 #endif
23
24 #ifndef _BITS_TYPESIZES_H
25 #define _BITS_TYPESIZES_H 1
26
27 /* See <bits/types.h> for the meaning of these macros. This file exists so
28 that <bits/types.h> need not vary across different GNU platforms.
宏定义参考types.h中的宏定义,如__S32_TYPE 这个是在types.h中定义的。
#define __S32_TYPE int
至于为什么要这么交叉定义,是为了使types.h不因为平台而发生变化。
因为,如果不同的平台的话,我们只需要改变typesizes.h就可以了。
*/
31 #define __UID_T_TYPE __U32_TYPE
32 #define __GID_T_TYPE __U32_TYPE
39 #define __PID_T_TYPE __S32_TYPE
53 #define __DADDR_T_TYPE __S32_TYPE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们以__key_t为例子来寻定义的蛛丝马迹:
1.__STD_TYPE __KEY_T_TYPE __key_t //bits/types.h
2.#define __KEY_T_TYPE __S32_TYPE //bits/typesizes.h
3.#define __S32_TYPE int
从3-2-1就是我们的: typedef int __key_t ;
至于我们看到的ipc中的key_t数据类型,则又是在__key_t基础上定义的,我们可以在ipc.h中找到这个定义:
47 #ifndef __key_t_defined
48 typedef __key_t key_t;
49 # define __key_t_defined
50 #endif
所以,我们在linux c 编程里面经常看到的那些莫名奇妙的数据类型,基本都可以通过以上方式找到最终的基本数据类型。