limits.h

薛定諤又死又生的貓發表於2015-12-07

我們知道過去的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

通過條件編譯,我們可以確定自己需求的返回。這要就能最大限度的節約資源,並且能滿足我們對數值範圍的要求。