limits.h
我們知道過去的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
通過條件編譯,我們可以確定自己需求的返回。這要就能最大限度的節約資源,並且能滿足我們對數值範圍的要求。