從學習C語言開始,int類型所占字節數,以及數值范圍就是一個揮之不去的問題。一開始會死記硬背一個char 1個字節,一個字節8個bit。64位機器上面一個int 4個字節,32位機器上面不一樣。那時候並不知道編譯器也分很多種,每一種實現的細節不一樣,也不知道各家編譯器是遵循C++標准委員會的標准。后來學會像編譯器求證,以其輸出為准,也學會向標准求證。
在一篇博客上面看到用numeric_limits 類可以方便地了解各個類型的取值范圍以及占用內存,於是滿心歡喜地將代碼運行,發現有些問題:
#include<iostream> #include <limits> using namespace std; int main() { cout << "type: \t\t" << "------------------size-----------------------"<< endl; cout << "bool: \t\t" << "Bytes:" << sizeof(bool); cout << "\tMaxValue:" << (numeric_limits<bool>::max)(); cout << "\t\tMinValue:" << (numeric_limits<bool>::min)() << endl; cout << "char: \t\t" << "Bytes:" << sizeof(char); cout << "\tMaxValue:" << (numeric_limits<char>::max)(); cout << "\t\tMinValue:" << (numeric_limits<char>::min)() << endl; cout << "signed char: \t" << "Bytes:" << sizeof(signed char); cout << "\tMaxValue:" << (numeric_limits<signed char>::max)(); cout << "\t\tMinValue:" << (numeric_limits<signed char>::min)() << endl; cout << "unsigned char: \t" << "Bytes:" << sizeof(unsigned char); cout << "\tMaxValue:" << (numeric_limits<unsigned char>::max)(); cout << "\t\tMinValue:" << (numeric_limits<unsigned char>::min)() << endl; cout << "wchar_t: \t" << "Bytes:" << sizeof(wchar_t); cout << "\tMaxValue:" << (numeric_limits<wchar_t>::max)(); cout << "\t\tMinValue:" << (numeric_limits<wchar_t>::min)() << endl; cout << "short: \t\t" << "Bytes:" << sizeof(short); cout << "\tMaxValue:" << (numeric_limits<short>::max)(); cout << "\t\tMinValue:" << (numeric_limits<short>::min)() << endl; cout << "int: \t\t" << "Bytes:" << sizeof(int); cout << "\tMaxValue:" << (numeric_limits<int>::max)(); cout << "\tMinValue:" << (numeric_limits<int>::min)() << endl; cout << "unsigned: \t" << "Bytes:" << sizeof(unsigned); cout << "\tMaxValue:" << (numeric_limits<unsigned>::max)(); cout << "\tMinValue:" << (numeric_limits<unsigned>::min)() << endl; cout << "long: \t\t" << "Bytes:" << sizeof(long); cout << "\tMaxValue:" << (numeric_limits<long>::max)(); cout << "\tMinValue:" << (numeric_limits<long>::min)() << endl; cout << "type: \t\t" << "************size**************"<< endl; return 0; }
運行結果:
常用的int,long等類型的取值范圍確實如願顯示。但是,在關於 char的判斷中,有顯示的問題。從使用的角度而言,其實char用於表示字符,判斷大小並不合理。當然,這只是一個“完形填空”式的推導。既然顯示在屏幕上的輸出有問題,本着鑽研精神,要弄清楚為什么。
首先是假設:
1. cout無法處理這個numeric_limit<char>::max()函數
2.numeric_limit<char>::max()的返回值並不是可顯示字符。
為了驗證第一點,我找到C++標准委員會的網站,找到C++14的草稿標准:
從這里看出,返回的是模板類型 T的構造函數。似乎排除了第一種可能。但標准太不具體,我在Clion上面用debug模式直接找到庫文件來確認。值得一提的是編譯器版本:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.2)。
第一步:
再往下一層:
在limits的實現里面,都是再用宏定義的位操作來實現最大和最小值的獲取。先看__glibcxx_digits宏定義。這里面的邏輯很簡單,占用字節數乘以__CHAR_BIT__減去符號位(1位)。在char的例子里面,得出來的位數是7。從這里不妨猜測,編譯器對一個字節大小的定義很有可能是基於__CHAR_BIT__的。在一篇博文看過對於古老的機器,char類型只有7bit。按照這個猜測,在描述內置int型大小的時候,就可以說一個int等於4個char。這個猜測挺有意思,不過有待考究。
進一步分析,__glicxx_min宏定義,對於傳入的類型_Tp,如果有符號,就執行(_Tp)1 << _glibcxx_digits(_Tp), 沒有就是(_Tp)0.
對於char型,它居然被是認為有符號的! 所以最小值的計算變成 (char)1 << 7,二進制表示10000000, -128.
一個被賦值為-128的char類型字符,其實現的動機難以理解,不過從某程度上說明標准與實現之間的距離,對於一個函數的實現,尤其是不常用的功能,最好還是自己進行確認。