深入理解C 列舉型別enum

2021-07-23 10:57:22 字數 4781 閱讀 5086

參考:

程式語言中的所有特性都是為了滿足某種需求,達到某個目的還出現.不會莫名其妙的出現在那.

列舉可以用來儲存一組屬性的值.enum的全稱是enumeration意思是列舉

看著這句話可能覺得太書面化了,不夠通俗易懂.那舉些通俗的例子說說.日常生活中我們特喜歡分類,比如讀書時分啥數,理,化.當官的級別有啥省長,市長,縣長.軍隊有軍長,師長,團長.這樣一組組的屬性值就最適合用列舉型別來表示.當用乙個軟體時,有些頁面會有很多單選按鈕(radio button),這也特別適合用列舉來表示你舉了哪乙個.

光這樣說你可能還不能體現列舉的好處.如果沒列舉,表示一些組屬性的值你只能用一組數字,或者一組字串.

數字從字面上看不出任意意義,可讀性非常差,所以很少用.那就假如要你通過比較字串來做很多種類判斷,比如 if(histitle == "stadholder")   else if(histtile == "mayor") .如果讓你敲個幾十次你就知道是件多麻煩痛苦的事了,很多單詞如果敲錯乙個意思就完全變了,這樣出現bug了也不容易找到.老是複製貼上也較麻煩.所以字串是編輯麻煩,容易出錯.如果要使用列舉就極大的方便我們敲**,整合開發工具中的智慧型感應會給你提示,敲個點號就帶出來了.而且列舉會做型別檢查,不會像字串那樣只能靠你自己去對比.

上面我們講了如果沒有列舉,一般會想到用數字或字串表示某個類別.這樣使用肯定不方便.也許你可能會想到用巨集來表示.比如#define 市長 "mayor" 或者#define 市長 2

這自然是乙個方法,但一來嘛在c++中是不太推薦用巨集的,盡量少用.因為c++是強型別的語言,希望通過型別檢查來降低程式中的很多錯誤,而巨集只是在編譯期前做簡單替換,繞過了型別檢查,失去了強型別系統的優勢支撐. 二來嘛一組屬性值都是相關聯的資訊,必須放到一起,放到一組.

關於常量的誤解

列舉型別成員是常量

這句話怎麼理解呢.也就是說enum  myenum ;

與 const int one = 1;  const int two = 2; const int three = 3; 差不多是一樣的.

說到常量其實有個非常誤導人的地方因為用巨集#define 可以定義的我們說是常量

,這裡只涉及到簡單的替換自然不可能存在記憶體分配問題.但是用const定義的也叫常量,而const定義常量貌似跟定義一般的變數只多個const關鍵字. 你可能會想當然認為常量都只是簡單替換,所以不存在記憶體分配.那按這個邏輯,豈不是const定義的常量,列舉型別都沒有記憶體分配?

實際上大部分時候確實是這樣的.但並非總是如此,有些情況會需要分配記憶體的.

如果定義常量const int one = 1;然後在其他地方只是把one作為右值賦值給其他變數那就不存在記憶體分配.但這裡的常量跟#define定義的常量不同,巨集定義的常量是編譯前簡單替換掉,而不需要做型別檢查.而const定義的常量在編譯時會幫型別檢查,

編譯完之後再做替換.所以編譯完之後就看不到const的資訊了,轉換成對應的值.const定義的資訊只是儲存在符號表中.

那同樣,如果只是enum myenum ;這樣定義乙個列舉型別,然後也是簡單的作右值賦值給其他變數.比如int num = myenum::one;那也只是儲存資訊在符號表中,編譯後被替換掉了.

有人可能說如果用sizeof myenum測下會發現會是4(這是vs裡面,不同的編譯器可能不一樣)於是認為不管是列舉裡面有多少個元素記憶體分配都是4.實際上不是這意思,應該是定義乙個myenum型別的列舉變數時會分配記憶體.這跟定義了乙個類一樣,你用sizeof去測乙個為也會看到大小,但我們知道只有當類例項化之後才實際分配記憶體的.

1.)const int one;是類的成員變數 2. )extern const int one = 123;    3.)const int one = 1;    int* pconst = &one;

上面三種情況會需要分配記憶體.

而列舉型別,如果不是簡單的去給其他變數賦值,而是去定義乙個列舉型別變數.

比如myenum grade = myenum::one; //此時會分配4位元組記憶體空間.(不過據說編譯器會做優化,如果列舉型別所有值用兩個位元組表示就足夠了,那實際分配的會就只會是兩位元組了.不一定就是預設的int型別的長度)

一般的用法是在全域性域內定義乙個列舉型別.比如

enum  myenum

如果不顯式指定,就會把第乙個值預設賦值為0,然後遞增1依次賦值.如果顯式指定了某個值,則它下乙個是它加1.

所以上面的例子中預設one = 0; two = 1; three= 2;

如果顯式指定enum myenum

則one = 0; two = 3; three = 4;

定義乙個列舉型別就是myenum grade = myenum::one;

類中使用列舉這是不太常用的用法.

在類中宣告乙個列舉後,定義列舉型別就可以省掉那個域作用字首.比如myenum my = one; 在相同的作用域內也不能出現某個變數的名字和列舉中的元素名字相同,也就是不能出現其他變數名字是on,two, three

另外列舉還有一種少見的用法是

enum ;  就是不指定乙個名字,這樣我們自然也沒法去定義一些列舉型別了.此時就相當於const int one = 0;這樣定義三個常量一樣.

然後用的話就是int no = one;

enum的秘密《一》:enum是「使用者自定義型別」

呵呵,enum在實際中應用比較少,所以你會忽略它。但是,在這裡,我告訴你,enum 和 struct、class一樣,都是使用者自定義型別。

對呀!enum是使用者自定義型別,他有資料成員,還有成員函式!

for example:

enum e;

那麼:001: enum e e1;        //enum e不是物件,它是型別,e1才是型別enum的物件!

002: e e1;                //e是型別enum e的簡寫哦!

003: e1 = 1;              //

絕對的錯誤!

int怎能賦值給乙個使用者自定義型別

004: e1 = e();            //e()? 對呀,你沒看錯,預設建構函式

005: e1 = e(1)           //e(int)? 嘿嘿,這才是從int構造enum e型別物件的建構函式

006:e1 = a;              //哈哈,預設呼叫「拷貝建構函式」···雖然有點不完備

大膽的想:enum會不會有使用者自定義成員函式呢?呵呵,我是沒有實驗出來。要不,你自己試試?

感想:c++雖然是初期的oo語言,但是型別化的概念已經深入到了語言本身。面對一門oo語言,你要必須知道一件事:

一切都是物件,一切都有型別···

enum的秘密《二》:enum的「取值範圍」和「記憶體分配」

先糾正乙個常見錯誤,很多人認為enum是個離散量集合,太理想化了^_^,簡單思考一下就破了,不多說,入正題:

如何確定乙個enum的取值範圍?

for example:

enum e1;

首先找到其絕對值的最大值,但為了容易理解,我先不談負數,也就是先找到其最大值,這裡的最大值是4。

4 用二進位制表示就是 100,也就是需要3bits才能最小的容納下4這個值,而3bits所能表示的範圍是 0-7,於是e1的取值範圍為[0,7]。

現在來看看負數,

enum e2;

其中絕對值最大的是4,需要3bits才能容納下,但因為可以取負值(而最大元素b=4不是負值),也就是說需要增加乙個符號位,那麼就需要4bits。

4bits的取值範圍是 1000 - 0111(二進位制表示),也就是 -8 到 7(十進位制表示)。

enum e3 就只需要3bits,取值範圍是[-4,3]。

簡單的說就是找到最少的能容納下所有的元素的位數

為什麼要獲取enum的取值範圍?

因為c++標準規定超出列舉型別表示範圍的賦值結果是undefined的

。也就是說 e2 x = (e2)6 是肯定正確的,而 e2 y = (e2)8 行為是未定義的。

undefined的含義我就不多說了,想怎麼去歪解就怎麼去歪解^_^

enum的記憶體分配呢?

比如 e2 需要3bits,那麼c++規定e2的尺寸

只要容得下

3bits

就行,到底是取1個byte,還是4個byte,還是...,那

由編譯器自己決定

。但是,c++標準在這裡有個限制:1<= sizeof(enmu)<=sizeof(int)。

類裡的const和enum 

下面的寫法有什麼問題嗎?

class bob

結果當然是編譯不通過。why?因為const在類物件裡進行了儲存空間分配,編譯器不能知道const的內容是什麼,所以不能把它用作編譯期間的常量。這意味著對於類裡的常數表示式來說,const就像它在c中一樣沒有作用。

在類裡的const意思是「在這個特定物件的壽命期內,而不是對於整個類來說,這個值是不變的」。那麼怎樣建立乙個可以用在常數表示式裡的類常量呢? 

乙個普通的辦法是使用乙個不帶例項的無標記的enum。列舉的所有值必須在編譯時建立,它對類來說是區域性的,但常數表示式能得到它的值,這樣,我們一般會看到:

class bob ;  // legal

int array[size]; // legal

}

使用enum是不會占用物件中的儲存空間的,列舉常量在編譯時被全部求值。我們也可以明確地建立列舉常量的值:enum ;

深入理解C 列舉型別enum

程式語言中的所有特性都是為了滿足某種需求,達到某個目的還出現.不會莫名其妙的出現在那.列舉可以用來儲存一組屬性的值 enum的全稱是enumeration意思是列舉 看著這句話可能覺得太書面化了,不夠通俗易懂.那舉些通俗的例子說說.日常生活中我們特喜歡分類,比如讀書時分啥數,理,化.當官的級別有啥省...

深入理解列舉型別enum

問題是git commit amend 引起的。一條commit已經push到遠端develop了,但是後來又在這條commit上進行了amend操作,導致這條commit的雜湊碼發生了變化。並且後續又在這條commit之後進行了n條commit操作。大概的情況畫了個簡圖,如圖所示。下面的綠色就是最...

C 深入理解型別

值型別 值型別通常儲存在棧中,值型別管理由作業系統管理 引用型別 引用型別儲存在堆中由gc管理 引用型別巢狀定義值型別 值型別巢狀引用型別 值型別繼承自valuetype,valuetype有繼承自system.object 引用型別直接繼承自system.object 值型別的記憶體不受gc控制,...