
建议2:防止整数类型产生回绕与溢出
到C99为止,C语言为我们提供了12个相关的数据类型关键字来表达各种数据类型。如表1-2所示,K&R C提供了7个,C89/C90新增了2个,C99新增了3个。
表1-2 C的数据类型关键字

整型是C语言最基本的数据类型,它以二进制编码的方式进行存储,具体可以包括字符、短整型、整型和长整型等。例如,整数2的二进制表示为10,它在8位与32位的操作系统中存储方式如图1-3所示。

图1-3 整数2的二进制编码存储方式
虽然在计算机中整数是以二进制编码方式进行存储的,但为了便于表达,有时候又会用十六进制编码方式表示(例如,在32位操作系统下,整数2的十六进制编码方式为0x00000002),二进制和十六进制之间能够很方便地进行转换。
与此同时,整数类型又可分为有符号(signed)和无符号(unsigned)两种类型,limits.h文件定义了整型数据类型的表达值范围。在GCC 4.8.3中,limits.h文件定义如下:
/* * ISO C99 Standard: 7.10/5.2.4.2.1 Sizes of integer types <limits.h> */ #ifndef _LIBC_LIMITS_H_ #define _LIBC_LIMITS_H_ 1 #include <features.h> /* Maximum length of any multibyte character in any locale. We define this value here since the gcc header does not define the correct value. */ #define MB_LEN_MAX 16 /* If we are not using GNU CC we have to define all the symbols ourself. Otherwise use gcc's definitions (see below). */ #if !defined __GNUC__ || __GNUC__ < 2 /* We only protect from multiple inclusion here, because all the other #include's protect themselves, and in GCC 2 we may #include_next through multiple copies of this file before we get to GCC's. */ # ifndef _LIMITS_H # define _LIMITS_H 1 #include <bits/wordsize.h> /* We don't have #include_next. Define ANSI <limits.h> for standard 32-bit words. */ /* These assume 8-bit `char's, 16-bit `short int's, and 32-bit `int's and `long int's. */ /* Number of bits in a `char'. */ # define CHAR_BIT 8 /* Minimum and maximum values a `signed char' can hold. */ # define SCHAR_MIN (-128) # define SCHAR_MAX 127 /* Maximum value an `unsigned char' can hold. (Minimum is 0.) */ # define UCHAR_MAX 255 /* Minimum and maximum values a `char' can hold. */ # ifdef __CHAR_UNSIGNED__ # define CHAR_MIN 0 # define CHAR_MAX UCHAR_MAX # else # define CHAR_MIN SCHAR_MIN # define CHAR_MAX SCHAR_MAX # endif /* Minimum and maximum values a `signed short int' can hold. */ # define SHRT_MIN (-32768) # define SHRT_MAX 32767 /* Maximum value an `unsigned short int' can hold. (Minimum is 0.) */ # define USHRT_MAX 65535 /* Minimum and maximum values a `signed int' can hold. */ # define INT_MIN (-INT_MAX - 1) # define INT_MAX 2147483647 /* Maximum value an `unsigned int' can hold. (Minimum is 0.) */ # define UINT_MAX 4294967295U /* Minimum and maximum values a `signed long int' can hold. */ # if __WORDSIZE == 64 # define LONG_MAX 9223372036854775807L # else # define LONG_MAX 2147483647L # endif # define LONG_MIN (-LONG_MAX - 1L) /* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */ # if __WORDSIZE == 64 # define ULONG_MAX 18446744073709551615UL # else # define ULONG_MAX 4294967295UL # endif # ifdef __USE_ISOC99 /* Minimum and maximum values a `signed long long int' can hold. */ # define LLONG_MAX 9223372036854775807LL # define LLONG_MIN (-LLONG_MAX - 1LL) /* Maximum value an `unsigned long long int' can hold. (Minimum is 0.) */ # define ULLONG_MAX 18446744073709551615ULL # endif /* ISO C99 */ # endif /* limits.h */ #endif /* GCC 2. */ #endif /* !_LIBC_LIMITS_H_ */ /* The <limits.h> files in some gcc versions don't define LLONG_MIN,LLONG_MAX, and ULLONG_MAX. Instead only the values gcc defined for ages are available. */ #if defined __USE_ISOC99 && defined __GNUC__ # ifndef LLONG_MIN # define LLONG_MIN (-LLONG_MAX-1) # endif # ifndef LLONG_MAX # define LLONG_MAX __LONG_LONG_MAX__ # endif # ifndef ULLONG_MAX # define ULLONG_MAX (LLONG_MAX * 2ULL + 1) # endif #endif
表1-3描述了以ANSI标准定义的整数类型。
表1-3 ANSI标准定义的整数类型

简单地讲,有符号和无符号整数间的区别在于怎样解释整数的最高位。如果定义一个有符号整数,则C编译程序生成的代码认为该数最高位是符号标志:符号标志为0,则该数为正;符号标志为1,则该数为负。
负数采用2的补码的形式来表示,即对原码各位求反(符号位除外),再将求反的结果加1,最后将符号位设置为1。例如,在32位操作系统中,有符号整数-2的存储方法如下。
第一步:取绝对值2的二进制编码。
00000000 00000000 00000000 00000010
第二步:求反(符号位除外)。
01111111 11111111 11111111 11111101
第三步:将求反的结果加1。
01111111 11111111 11111111 11111110
第四步:将符号位设置为1。
11111111 11111111 11111111 11111110
因此,有符号整数-2的二进制编码为11111111 11111111 11111111 11111110,十六进制编码为0xFFFFFFFE。
最后还需要说明的是,当类型修饰符被自身使用时(即它不在基本类型之前时),假定其为int型。也就是说,表1-4的两种类型是等效的。
表1-4 等效的整数类型
