当Linux内核在体系结构差异较大的平台之间移植时,会产生与数据类型相关的问题。在编译内核时使用 -Wall -Wstrict-prototypes选项,可以避免很多错误的发生。
内核使用的基本数据类型主要有:
ØØ int 标准C语言整数类型;
ØØ u32 32位整数类型;
ØØ pid_t 特定内核对象pid的类型。
在不同的CPU体系结构上,C语言的数据类型所占空间不一样。下面是在x86下数据类型所占的字节数:
|
arch |
char |
short |
int |
long |
ptr |
long-long |
u8 |
u16 |
u32 |
u64 |
|
i686 |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
下面是在其他平台上的数据类型所占的字节数:
|
arch |
char |
short |
int |
long |
ptr |
long-long |
u8 |
u16 |
u32 |
u64 |
|
i386 |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
|
alpha |
1 |
2 |
4 |
8 |
8 |
8 |
1 |
2 |
4 |
8 |
|
armv4l |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
|
ia64 |
1 |
2 |
4 |
8 |
8 |
8 |
1 |
2 |
4 |
8 |
|
m68k |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
|
mips |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
|
ppc |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
|
sparc |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
|
sparc64 |
1 |
2 |
4 |
4 |
4 |
8 |
1 |
2 |
4 |
8 |
其中基于sparc64平台的Linux用户空间可以运行32位代码,用户空间指针是32位宽的,但内核空间是64位的。
内核中的地址是unsigned long类型,指针大小和long类型相同。
内核提供下列数据类型。所有类型在头文件<asm/types.h>中声明,这个文件又被头文件<Linux/types.h>所包含。下面是include/asm/types.h文件。
#ifndef _I386_TYPES_H
#define _I386_TYPES_H
#ifndef __ASSEMBLY__
typedef unsigned short umode_t;
// 下面__xx类型不会损害POSIX 名字空间,在头文件使用它们,可以输出显露给用户空间
typedef __signed__ char __s8;
typedef unsigned char __u8;
typedef __signed__ short __s16;
typedef unsigned short __u16;
typedef __signed__ int __s32;
typedef unsigned int __u32;
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
typedef __signed__ long long __s64;
typedef unsigned long long __u64;
#endif
#endif /* __ASSEMBLY__ */
//下面的类型只用在内核中,否则会产生名字空间崩溃
#ifdef __KERNEL__
#define BITS_PER_LONG 32
#ifndef __ASSEMBLY__
#include <Linux/config.h>
typedef signed char s8;
typedef unsigned char u8;
typedef signed short s16;
typedef unsigned short u16;
typedef signed int s32;
typedef unsigned int u32;
typedef signed long long s64;
typedef unsigned long long u64;
/* DMA addresses come in generic and 64-bit flavours. */
#ifdef CONFIG_HIGHMEM64G
typedef u64 dma_addr_t;
#else
typedef u32 dma_addr_t;
#endif
typedef u64 dma64_addr_t;
#ifdef CONFIG_LBD
typedef u64 sector_t;
#define HAVE_SECTOR_T
#endif
typedef unsigned short kmem_bufctl_t;
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif
下面是Linux/types.h的部分定义。
#ifndef _LINUX_TYPES_H
#define _LINUX_TYPES_H
#ifdef __KERNEL__//这个宏定义必须在#include < asm /types.h>之前
#include <Linux/config.h>
#define BITS_TO_LONGS(bits) \
(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
#define DECLARE_BITMAP(name,bits) \
unsigned long name[BITS_TO_LONGS(bits)]
#endif
#include <Linux/posix_types.h>
#include <asm/types.h>
u8; /* unsigned byte (8 bits) */
u16; /* unsigned word (16 bits) */
u32; /* unsigned 32-bit value */
u64; /* unsigned 64-bit value */
使用有前缀的类型用于将变量显露给用户空间,如_ _u8类型。例如:一个驱动程序通过ioctl函数与运行在用户空间的程序交换数据,应该用_ _u32来声明32位的数据类型。
有时内核使用C语言的类型,如unsigned int,这通常用于大小独立于体系结构的数据项。
内核中许多数据类型由typedef声明,这样方便移植。如使用pid_t类型作为进程标志符(pid)的类型,而不是int类型,pid_t屏蔽了在不同平台上的实际数据类型的差异。
如果不容易选择合适的类型,就将其强制转换成最可能的类型(long或unsigned long)。






