我们知道过去的IEEE1003.1标准,也叫做POSIX。C中的一个优良传统是标量数据类型要以一种对每个计算机体系结构都很自然的方式表示。这个名叫limits.h的头文件更应该叫integer.h和float.h对应,但是因为linits.h的名字比float.h先出现。因为历史的连贯性战胜了格式的整齐,所以名字一直未变。
limits.h头文件代码如下:
#ifndef MY_LIMITS_H
#define MY_LIMITS_H
#ifndef MY_YVALS_H
#include "my_yvals.h"
#endif
/**char properties*/
#define CHAR_BIT
#if _CSIGN
#define CHAR_MAX 127
#define CHAR_MIN (-127 - _C2) /**由my_yvals.h可知_C2为1*/
#else
#define CHAR_MAX 255
#define CHAR_MIN 0
#endif // _CSIGN
#if _ILONG
#define INT_MAX 2147483647
#define INT_MIN (-2147483647 - _C2)
#define UINT_MAX 4294967295
#else
#define INT_MAX 32767
#define INT_MIN (-32767 - _C2)
#define UINT_MAX 65535
#endif // _ILONG
#define LONG_MAX 2147483647
#define LONG_MIN (-2147483647 - _C2)
#define MB_LEN_MAX _MBMAX
#define SCHAR_MAX 127
#define SCHAR_MIN (-127 - _C2)
#define SHRT_MAX 32767
#define SHRT_MIN (-32767 - _C2)
#define UCHAR_MAX 255
#define ULONG_MAX 4294967295
#define USHRT_MAX 65535
#endif
定义了基本整数类型的范围。这个头文件的定义时间是非常早的。大概在90年代之前,现在已经是2015年。有些定义的极值已经改变,比如int、long int。比如如下代码(我在自己的机器上做的测试):
#include <stdio.h>
#include <limits.h>
int main()
{
printf("INT_MIN:%d\n", INT_MIN);
printf("十进制符号常量:%d\n", -2147483648);/**warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]*/
printf("LONG_MIN%d\n", LONG_MIN);
printf("十进制符号常量:%ld\n", -9223372036854775808);/**warning: integer constant is so large that it is unsigned [enabled by default]*/
printf("ULONG_MAX:%lu\n", ULONG_MAX);/**ULONG_MAX为18446744073709551615*/
printf("%lu\n", 18446744073709551617);/**溢出,输出结果为1*/
return 0;
}
注意注释里的警告,这是笔者用的gcc编译器给出的警告。虽然数值上和标准头文件limits.h定义的一样,但是会有警告。请仔细看limits.h头文件关于INT_MIN和LONG_MIN的宏定义。并不是直接赋予的一个明显的值。这可以解释为在一个64位的机器(我用的是ubuntu14.04 64位,在这个机器上int占4个字节,long int占8个字节)上,字符序列-2147483648被分解为2个符号,一个负号和一个值为2147483648的整型常量,后者为long类型(因为这个数值太大了,没法用int类型表示,int最大值才2147483647)。对这个值取负并不会改变它的类型(仍然是long int),但是C标准要求INT_MIN的类型为int,所以用的是一个表达式,而不是一个直接的明显的值。
我们可以规定一个我们自己的整数类型,比如:
#include <limits.h>
#if VAL_MIN < INT_MIN || VAL_MAX > INT_MAX
typedef long Val_t;
#else
typedef int Val_t;
#endif
通过条件编译,我们可以确定自己需求的返回。这要就能最大限度的节约资源,并且能满足我们对数值范围的要求。