c语言数据类型

来源:互联网 发布:什么是美工设计助理 编辑:程序博客网 时间:2024/06/06 06:48
在debian4.3.5上 测试结果:     u_int64_t:头文件 stdlib.h     uint64_t:头文件 stdint.h--------------------------------------------------我是分割线------------------------------------一、数据类型特别是int相关的类型在不同位数机器的平台下长度不同。C99标准并不规定具体数据类型的长度大小,只规定级别。作下比较:

16位平台

char      1个字节8位
short       2个字节16位
int         2个字节16位
long       4个字节32位
指针       2个字节

32位平台

char       1个字节8位
short       2个字节16位
int         4个字节32位
long       4个字节
long long 8个字节
指针       4个字节

64位平台

char       1个字节
short       2个字节
int         4个字节
long       8个字节(区别)
long long 8个字节
指针       8个字节(区别)

二、编程注意事项

为了保证平台的通用性,程序中尽量不要使用long数据库型。可以使用固定大小的数据类型宏定义:

typedef signed char     int8_t

typedef short int         int16_t;

typedef int                int32_t;

# if __WORDSIZE == 64
typedef long int          int64_t;
# else
__extension__
typedef long long int    int64_t;

#endif

三、使用int时也可以使用intptr_t来保证平台的通用性,它在不同的平台上编译时长度不同,但都是标准的平台长度,比如64位机器它的长度就是8字节,32位机器它的长度是4字节,定义如下:

#if __WORDSIZE == 64
typedef long int           intptr_t;
#else
typedef int                 intptr_t;
#endif
编程中要尽量使用sizeof来计算数据类型的大小

以上类型定义都有相应的无符号类型。

另外还有ssize_t和size_t分别是sign size_t和unsigned signed size of computerwordsize。它们也是表示计算机的字长,在32位机器上是int型,在64位机器上long型,从某种意义上来说它们等同于intptr_t和uintptr_t。它们在stddef.h里面定义。需要注意的是socket的accept函数在有些操作系统上使用size_t是不正确的,因为accept接收的int*类型,而size_t可能是long int 类型。后来BSD使用sock_t来替代它。----------------------------------------------------我是分割线----------------------------------- 在标准头文件发明以前就有了用户自定义类型。u_ 用户自定义, useru -- 无符号 unsigned

一般来说,一个C的工程中一定要做一些这方面的工作,因为你会涉及到跨平台,不同的平台会有不同的字长,所以利用预编译和typedef可以让你最有效的维护你的代码。为了用户的方便,C99标准的C语言硬件为我们定义了这些类型,我们放心使用就可以了。

 按照posix标准,一般整形对应的*_t类型为:1字节     uint8_t2字节     uint16_t4字节     uint32_t8字节     uint64_t

 

pecific integral type limitsSpecifierCommon EquivalentSigningBitsBytesMinimum ValueMaximum Valueint8_tsigned charSigned81−128127uint8_tunsigned charUnsigned810255int16_tshortSigned162−32,76832,767uint16_tunsigned shortUnsigned162065,535int32_tintSigned324−2,147,483,6482,147,483,647uint32_tunsigned intUnsigned32404,294,967,295int64_tlong longSigned648−9,223,372,036,854,775,8089,223,372,036,854,775,807uint64_tunsigned long longUnsigned648018,446,744,073,709,551,615

 

 

上面是一些与平台无关的数据类型,由于在32位机器和64位机器中,long占据不同的字节数,所以推荐使用上面的类型。。上面的类型的头文件是stdint.h

当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类型相同。

内核提供下列数据类型。所有类型在头文件<include/asm/types.h>中声明,这个文件又被头文件<Linux/types.h>所包含。下面是include/asm/types.h文件。这是对ARM体系结构中 /asm/types.h文件中的一些定义: 因为我是对arm体系结构进行了配置

#ifndef __ASM_ARM_TYPES_H #define __ASM_ARM_TYPES_H #ifndef __ASSEMBLY__ typedef unsigned short umode_t; /*  * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the  * header files exported to user space  */ 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__ */ /*  * These aren't exported outside the kernel to avoid name space clashes  */ #ifdef __KERNEL__ #define BITS_PER_LONG 32 #ifndef __ASSEMBLY__ 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 are 32-bits wide. */ typedef u32 dma_addr_t; typedef u32 dma64_addr_t; #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif

 

 

使用有前缀的类型用于将变量显露给用户空间,如_ _u8类型。例如:一个驱动程序通过ioctl函数与运行在用户空间的程序交换数据,应该用_ _u32来声明32位的数据类型。

有时内核使用C语言的类型,如unsigned int,这通常用于大小独立于体系结构的数据项。 内核中许多数据类型由typedef声明,这样方便移植。如使用pid_t类型作为进程标志符(pid)的类型,而不是int类型,pid_t屏蔽了在不同平台上的实际数据类型的差异。

如果不容易选择合适的类型,就将其强制转换成最可能的类型(long或unsigned long)。

如上面所说,在<include/linux/types.h>中又把你所配置的体系结构中定义的类型的类型定义

<include/asm/types.h>包含进去了:下面把<include/linux/types.h>这个文件贴出来,我的内核版本是2.6.16.28。

 

 

#ifndef _LINUX_TYPES_H #define _LINUX_TYPES_H #ifdef    __KERNEL__ #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)] #define BITS_PER_BYTE 8 #endif #include <linux/posix_types.h> #include <asm/types.h> #ifndef __KERNEL_STRICT_NAMES typedef __u32 __kernel_dev_t; typedef __kernel_fd_set        fd_set; typedef __kernel_dev_t        dev_t; typedef __kernel_ino_t        ino_t; typedef __kernel_mode_t        mode_t; typedef __kernel_nlink_t    nlink_t; typedef __kernel_off_t        off_t; typedef __kernel_pid_t        pid_t; typedef __kernel_daddr_t    daddr_t; typedef __kernel_key_t        key_t; typedef __kernel_suseconds_t    suseconds_t; typedef __kernel_timer_t    timer_t; typedef __kernel_clockid_t    clockid_t; typedef __kernel_mqd_t        mqd_t; #ifdef __KERNEL__ typedef __kernel_uid32_t    uid_t; typedef __kernel_gid32_t    gid_t; typedef __kernel_uid16_t uid16_t; typedef __kernel_gid16_t gid16_t; #ifdef CONFIG_UID16 /* This is defined by include/asm-{arch}/posix_types.h */ typedef __kernel_old_uid_t    old_uid_t; typedef __kernel_old_gid_t    old_gid_t; #endif /* CONFIG_UID16 */ /* libc5 includes this file to define uid_t, thus uid_t can never change  * when it is included by non-kernel code  */ #else typedef __kernel_uid_t        uid_t; typedef __kernel_gid_t        gid_t; #endif /* __KERNEL__ */ #if defined(__GNUC__) && !defined(__STRICT_ANSI__) typedef __kernel_loff_t        loff_t; #endif /*  * The following typedefs are also protected by individual ifdefs for  * historical reasons:  */ #ifndef _SIZE_T #define _SIZE_T typedef __kernel_size_t        size_t; #endif #ifndef _SSIZE_T #define _SSIZE_T typedef __kernel_ssize_t    ssize_t; #endif #ifndef _PTRDIFF_T #define _PTRDIFF_T typedef __kernel_ptrdiff_t    ptrdiff_t; #endif #ifndef _TIME_T #define _TIME_T typedef __kernel_time_t        time_t; #endif #ifndef _CLOCK_T #define _CLOCK_T typedef __kernel_clock_t    clock_t; #endif #ifndef _CADDR_T #define _CADDR_T typedef __kernel_caddr_t    caddr_t; #endif /* bsd */ typedef unsigned char        u_char; typedef unsigned short        u_short; typedef unsigned int        u_int; typedef unsigned long        u_long; /* sysv */ typedef unsigned char        unchar; typedef unsigned short        ushort; typedef unsigned int        uint; typedef unsigned long        ulong; #ifndef __BIT_TYPES_DEFINED__ #define __BIT_TYPES_DEFINED__ typedef        __u8        u_int8_t; typedef        __s8        int8_t; typedef        __u16        u_int16_t; typedef        __s16        int16_t; typedef        __u32        u_int32_t; typedef        __s32        int32_t; #endif /* !(__BIT_TYPES_DEFINED__) */ typedef        __u8        uint8_t; typedef        __u16        uint16_t; typedef        __u32        uint32_t; #if defined(__GNUC__) && !defined(__STRICT_ANSI__) typedef        __u64        uint64_t; typedef        __u64        u_int64_t; typedef        __s64        int64_t; #endif /* this is a special 64bit data type that is 8-byte aligned */ #define aligned_u64 unsigned long long __attribute__((aligned(8))) /*  * The type used for indexing onto a disc or disc partition.  * If required, asm/types.h can override it and define  * HAVE_SECTOR_T  */ #ifndef HAVE_SECTOR_T typedef unsigned long sector_t; #endif /*  * The type of an index into the pagecache. Use a #define so asm/types.h  * can override it.  */ #ifndef pgoff_t #define pgoff_t unsigned long #endif #endif /* __KERNEL_STRICT_NAMES */ /*  * Below are truly Linux-specific types that should never collide with  * any application/library that wants linux/types.h.  */ #ifdef __CHECKER__ #define __bitwise__ __attribute__((bitwise)) #else #define __bitwise__ #endif #ifdef __CHECK_ENDIAN__ #define __bitwise __bitwise__ #else #define __bitwise #endif typedef __u16 __bitwise __le16; typedef __u16 __bitwise __be16; typedef __u32 __bitwise __le32; typedef __u32 __bitwise __be32; #if defined(__GNUC__) && !defined(__STRICT_ANSI__) typedef __u64 __bitwise __le64; typedef __u64 __bitwise __be64; #endif #ifdef __KERNEL__ typedef unsigned __bitwise__ gfp_t; #endif struct ustat {     __kernel_daddr_t    f_tfree;     __kernel_ino_t        f_tinode;     char            f_fname[6];     char            f_fpack[6]; }; #endif /* _LINUX_TYPES_H */

 

 

这里面我以可以看到一些自定义类型,如loff_t,size_t等。

typedef __kernel_uid_t        uid_t;typedef __kernel_gid_t        gid_t;

typedef __kernel_loff_t        loff_t;

这样就将loff_t类型定义为__kernel_loff_t这个类型了,uid_t类型定义了__kernel_uid_t类型了,但是现在__kernel_loff_t __kernel_uid_t这种类型是很明显地与体系结构是相关的,对于arm的体系结构,则定义在<include/asm-arm/posix_types.h>,代码如下:

 

 

/* * linux/include/asm-arm/posix_types.h * * Copyright (C) 1996-1998 Russell King. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Changelog: * 27-06-1996    RMK    Created */#ifndef __ARCH_ARM_POSIX_TYPES_H#define __ARCH_ARM_POSIX_TYPES_H/* * This file is generally used by user-level software, so you need to * be a little careful about namespace pollution etc. Also, we cannot * assume GCC is being used. */typedef unsigned long        __kernel_ino_t;typedef unsigned short        __kernel_mode_t;typedef unsigned short        __kernel_nlink_t;typedef long            __kernel_off_t;typedef int            __kernel_pid_t;typedef unsigned short        __kernel_ipc_pid_t;typedef unsigned short        __kernel_uid_t;typedef unsigned short        __kernel_gid_t;typedef unsigned int        __kernel_size_t;typedef int            __kernel_ssize_t;typedef int            __kernel_ptrdiff_t;typedef long            __kernel_time_t;typedef long            __kernel_suseconds_t;typedef long            __kernel_clock_t;typedef int            __kernel_timer_t;typedef int            __kernel_clockid_t;typedef int            __kernel_daddr_t;typedef char *            __kernel_caddr_t;typedef unsigned short        __kernel_uid16_t;typedef unsigned short        __kernel_gid16_t;typedef unsigned int        __kernel_uid32_t;typedef unsigned int        __kernel_gid32_t;typedef unsigned short        __kernel_old_uid_t;typedef unsigned short        __kernel_old_gid_t;typedef unsigned short        __kernel_old_dev_t;#ifdef __GNUC__typedef long long        __kernel_loff_t;#endiftypedef struct {#if defined(__KERNEL__) || defined(__USE_ALL)    int    val[2];#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */    int    __val[2];#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */} __kernel_fsid_t;#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)#undef    __FD_SET#define __FD_SET(fd, fdsetp) /        (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31)))#undef    __FD_CLR#define __FD_CLR(fd, fdsetp) /        (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31)))#undef    __FD_ISSET#define __FD_ISSET(fd, fdsetp) /        ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0)#undef    __FD_ZERO#define __FD_ZERO(fdsetp) /        (memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp))))#endif#endif
0 0
原创粉丝点击