C++變量和基本類型詳解
基本內置類型
算術類型分為兩類:整型(包括字符和佈爾類型在內)和浮點型
1. 不同平臺下基本類型的字節數
類型 | 16位平臺 | 32位平臺 | 64位平臺 |
---|---|---|---|
char | 1 | 1 | 1 |
short | 2 | 2 | 2 |
int | 2 | 4 | 4 |
long | 4 | 4 | 8 |
long long | / | 8 | 8 |
指針 | 2 | 4 | 8 |
float | 4 | 4 | 4 |
double | 8 | 8 | 8 |
數據類型long long 是在C++11中新定義的。
2. 算數類型的最小尺寸
算術類型分為兩類:整型(包括字符和佈爾類型在內)和浮點型
類型 | 含義 | 最小尺寸 |
---|---|---|
bool | 佈爾類型 | 未定義 |
char | 字符 | 8位 |
wchar_t | 寬字符 | 16位 |
char16_t | Unicode字符 | 16位 |
char32_t | Unicode字符 | 32位 |
short | 短整型 | 16位 |
int | 整型 | 16位 |
long | 長整型 | 32位 |
long long | 長整型 | 64位 |
float | 單精度浮點數 | 6位有效數字 |
double | 雙精度浮點數 | 10位有效數字 |
long double | 擴展雙精度浮點數 | 10位有效數字 |
3. 數據類型選擇的經驗準則
- 當知曉數值不可能為負時,選用無符號類型
- 使用int執行整數運算,short常常太小,long和int一般尺寸一樣。如果int不夠,用long long。
- 在算數表達式中不要使用char或bool,使用char特別容易出問題。如果要使用一個不大的整數,那麼明確執行為signed char或unsigned char。
- 執行浮點數運算用double,float通常進度不夠而且兩者計算代價相差無幾。Long double一般沒有必要,且消耗不容忽視。
4. 有符號類型和無符號類型
- 無符號類型賦值超出其范圍,結果是取模後的值。如unsigned char c = -1; //假設char占8bit,c的值為255
- 有符號類型賦值超出其范圍,結果未定義。如signed char c2 = 256; //假設char占8bit,c2的值未定義
- 切勿混用帶符號類型和無符號類型。
- 算數表達式中既有無符號數又有帶符號數,帶符號的數會轉換成無符號的數
5.初始化與賦值
初始化和賦值是兩個完全不同的操作。
- 定義於任何函數體外的之外的變量被初始化成0
- 定義於函數體(塊作用域)內的內置類型的對象如果沒有初始化,則其值未定義。養成初始化內置變量的習慣。
- 類的對象如果沒有顯式地初始化,則其值由類確定。
6. 聲明與定義
- 聲明使得一個名字為程序所知,定義會申請存儲空間,還可能為其賦初始值
- (分離式編譯) 如果想聲明一個變量而非定義它,就在變量名前添加關鍵字extern,而且不要顯式地初始化變量
- 對於復雜的聲明語句,可以從變量名從右往左理解
- 變量能且隻能被定義一次,但是可以被多次聲明
7. C++關鍵字
8. const
8.1 初始化
默認狀態下,const對象僅在文件內有效。
在編譯的過程中,編譯器會把所有用到該const變量的地方都替換成相應的值。所以編譯器必須知道變量的初始值,如果存在多個文件的情況下,每個文件必須知道const的初始值(const對象也必須初始化)。但由於默認狀態下,const對象僅在文件內有效,當多個文件同時出現同名的const變量時,其實就相當於分別定義瞭不同的變量。
如果想隻定義一次怎麼做呢?
隻需要無論是聲明還是定義都標記extern關鍵字即可。
//file1.cpp extern const i=1; //file2.cpp extern const i;
如果想要在多個文件之間共享const 對象,必須在變量之前添加extern關鍵字
8.2 const引用
定義:把引用綁定到const對象上,即為對常量的引用(reference to const)。
引用類型必須與其所引用對象類型一致(但是有兩個例外),
8.2.1 與普通引用不同的是不能讓非常量引用指向一個常量變量。
int i= 0; const int &ci = i; int &ri = ci;
因為非常量引用可以修改它所綁定的對象,但是常量引用不能,如果非常量引用指向一個常量變量合理的話,那麼非常量引用可以修改它所綁定的對象的值,這顯然是不正確的。
8.2.2 初始化常量引用時允許將以任意表達式作為初始值,隻要表達式的結果能轉換成對應類型即可。
8.2.2.1允許常量引用綁定分常量的對象、字面值,甚至一個一般表達式
double dval = 3.14; const int &ri = dval; std::cout<<"dval:"<<dval<<std::endl; std::cout<<"ri:"<<ri<<std::endl;
編譯器會將上面代碼變成:
const int temp= dval; const int &ri = temp; std::cout<<"dval:"<<dval<<std::endl; std::cout<<"ri:"<<ri<<std::endl;
在這種情況下面,ri綁定瞭一個臨時量
ri不是常量引用的時候會發生錯誤:
double dval = 3.14; int &ri = dval; // error: invalid initialization of non-const reference of type ‘int&' from an rvalue of type ‘int' std::cout<<"dval:"<<dval<<std::endl; std::cout<<"ri:"<<ri<<std::endl;
編譯器會將上面代碼變成:
int temp= dval; int &ri = temp; std::cout<<"dval:"<<dval<<std::endl; std::cout<<"ri:"<<ri<<std::endl;
由於臨時值的特殊性,程序員並不能操作臨時值,而且臨時值隨時可能被釋放掉,所以,一般說來,修改一個臨時值是毫無意義的,據此,c++編譯器加入瞭臨時值不能作為非const引用的這個語義限制。
8.2.2.2 const引用可能用一個非const對象
int i =0; int &ri = i; const int &ci = i; ci = 2; // error: assignment of read-only reference ‘ci'
常量引用僅對引用可參與的操作做出限定,對於引用的對象本身是不是一個長量未作限定
8.3 const與指針
指針的類型必須與其所指對象的類型一致(但是有兩個例外)
允許一個指向常量的指針指向一個非常量對象.
和const引用差不多,指針常量的指針也沒有規定所指的對象必須是一個常量
8.3.1 指向常量的指針和常量指針
指向常量的指針(指針可以改變,指針的值不可變):
const int x=1; const int *p = &x;//p為指向常量x的指針 int *p = &x; //錯誤,因為p隻是個普通指針
常量指針(不變的指針而不是指針指向的值):
int x=0; int *const p = &x;//p為常量指針(允許一個指向常量的指針指向一個非常量對象.) const int xx=0; const int *const pp= &xx;//pp為指向常量的常量指針(
int x=0; int y = 11; const int *p = &x;//p為常量指針(允許一個指向常量的指針指向一個非常量對象.) int *const cp = &x; const int *const pp= &x;//pp為指向常量的常量指針 x = 1; std::cout<<"x:"<<x<<std::endl; std::cout<<"*p:"<<*p<<std::endl; std::cout<<"*cp:"<<*cp<<std::endl; std::cout<<"*PP:"<<*pp<<std::endl; p = &y; *p = 11; // error: assignment of read-only location ‘* p' *cp = 12; cp = &y;// error: assignment of read-only variable ‘cp' std::cout<<"*p:"<<*p<<std::endl; std::cout<<"*cp:"<<*cp<<std::endl;
小結:
常量指針,指針本身是一個常量,不可以改變指向的對象,但是可以改變指向對象的值,可以使用解引符改變地址所指向的值
指向常量的指針,可以重新指定指向新的對象,但是不可以改變對象的值.
int errNumb =0; int *const curErr = &errNumb; // curerr 將一直指向errNumb errNumb 的值變化瞭curerr的值也跟著變化 const double pi = 3.14159; const double *const pip = π // pip 是一個指向常量對象的常量指針 std::cout<<"curErr:"<<*curErr<<std::endl; std::cout<<"pip:"<<*pip<<std::endl; errNumb =1; std::cout<<"curErr:"<<*curErr<<std::endl;
輸出:
curErr:0
pip:3.14159
8.3.2 頂層const和底層const
指針如果添加const修飾符時有兩種情況:
頂層const:表示指針本身是一個常量
底層const:表示指針所指向的對象是一個常量
9. constexpr 和常量表達式
常量表達式(const experssion):是指
1.值不會改變 並且
2.在編譯過程就能得到計算結果的表達式。
字面量屬於常量表達式,用常量表達式初始化的const對象也是常量表達式。
9. 1 constexpr 變量:
一般來說,如果 你認定變量是一個常量表達式,那就把它聲明成constexpr類型函數:
constexpr函數是指能用於常量表達式的函數。
應遵循的約定:函數返回類型及所有形參的類型都是字面值類型,而且函數體中必須有且隻有一條return 語句。
constexpr函數體內可以有其他語句,隻要這些語句在運行時不執行任何操作。(例如,空語句、類型別名和using聲明等)
constexpr函數被隱式地指定為內聯函數。
9. 2字面值類型
常量表達式的值需要在編譯時就得到計算,因此對聲明constexpr時用到的類型必須有所限制。因為這些類型一般比較簡單,值也顯而易見、容易得到,就把它們稱為“字面值類型”(literal type)。
字面值類型范圍:
算術類型、引用和指針都屬於字面值類型。某些類也是字面值類型,它們可能含有constexpr函數成員。自定義類Sales_item、IO庫、string類型不屬於字面值類型。
9. 3constexpr 和指針
盡管指針和引用可以定義成constexpr,但它們的初始值受到嚴格限制。一個constexpr指針的初始值必須是nullptr、0或存儲於某個固定地址中的對象。
constexpr int *q = nullprt 等價於 int const *q = nullprt
函數體內定義的變量一般來說並非存放在固定地址中,因此constexpr指針不能指向這樣的變量。定義於函數體外的對象其地址固定不變,能用來初始化constexpr指針。
允許函數定義一類有效范圍超出函數本身的變量,如局部靜態變量,這類變量和定義在函數體之外的變量一樣有固定地址,因此constexpr引用能綁定到這樣的變量上,constexpr指針也能指向這樣的變量。
10. 處理類型
10.1 類型別名 typeof
typedef double a; typedef wages base,*p; //等價於 double base ,*p;
using
using SI = Sales_item; SI item;//等價於 Sales_item item;
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- C++學習之算術運算符使用詳解
- c++primer:變量和基本類型詳解
- 一文帶你分清C++的定義,聲明和初始化
- 一篇文章帶你瞭解C++Primer學習日記–處理數據
- C++右值引用與移動構造函數基礎與應用詳解