今天說說C語言中的枚舉。
參考:Enumeration (or enum) in C
1 定義
定義一個枚舉類型很容易:
enum aa { a1, a2, a3 };
這里
- enum是關鍵字
- aa是枚舉變量,也就是我們自定義類型
- a1,a2,a3是枚舉成員
然后怎么使用呢?
首先,它就像結構體struct
和聯合體union
那樣,是一個自定義的數據類型,用它定義變量,也是一樣的:
enum aa abc; // 定義變量
enum aa *en_p; // 定義指針
是的,它跟基本數據類型以及結構體等特殊數據類型一樣,都可以定義變量和定義指針。
所以,和int
一樣,如果僅僅定義,而沒有賦值和使用,編譯后它就沒了,變量定義本身不占地方,賦值了才占地方。
另外,和struct
一樣,它只是一個結構,這個結構是C語言層級的聲明,編譯后不存在這個結構的,匯編層級沒有的。
所以,下面我們先說說,變量的賦值
2 變量的賦值
枚舉類型的賦值其實是比較復雜的,先說最常用的。
2.1 默認值
enum aa { a1, a2, a3 };
對于上述枚舉類型,它的a1 a2 a3
, 在默認情況下,會被賦值為
a1 = 0;
a2 = 1;
a3 = 2;
2.2 賦初值
enum aa { a1 = 1, a2 = 3, a3 = 5 };
可以對其任意賦初值,這樣,三個枚舉成員的值就對應了你指定的值了。
我們看看多種情況:
情況1:全都賦初值
enum aa { a1 = 1, a2 = 3, a3 = 5 };
情況2:有重復的初值
這種情況的完全可以的。
enum aa { a1 = 1, a2 = 1, a3 = 5 };
情況3:部分賦初值,部分不賦值
enum aa { a1 = 1, a2, a3 };
對于此時,a2 = 2 a3 = 3
,也就是說,后面沒有賦值的,是默認根據前面賦值的累加的。
enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };
那這種情況呢?
- 根據a1累加:
a2 = 2 a3 = 3 a4 = 4
- 根據a4累加:
a5 = 11 a6 = 12
賦值范圍
與int類型賦值范圍一樣!賦值-1
什么的也可以,與int類型的范圍一樣的。
2.3 變量賦值
其實就是定義一個變量,然后給它賦值,這里不一樣的是,枚舉成員本身,就代表值。
enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };
enum aa abc = a2;
這個時候,abc = 2
,a2就代表數值2.
從其他角度理解,enum aa abc = a2;
的含義就是
int a2 = 2;
int abc = a2;
就是這么個意思。
2.4 指針賦值
enum aa abc = a2;
enum aa *enu_p = &abc;
printf("%d\n", *enu_p);
沒啥好說的,跟基本數據類型指針待遇一樣的。
3 談談枚舉成員
3.1 作用范圍
首先,結構體本身
enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };
它的作用范圍,跟struct
一樣,跟int
也一樣,在{ }
里面就是局部變量,在最外面就是全局變量,對于aa
這個自定義類型標識符,也是一樣的,不多說了。
比較需要注意的是,枚舉成員也是標識符。
3.2 枚舉成員也是標識符
我們上面的例子,a1,a2,a6
這些,在其作用域內,也是標識符,也就是相當于你定義了一個int a1;
一樣,在作用域內不能重復定義了!并且,這個標識符本身代表了一個int值。
int main(){enum aa { a1 = 1, a2, a3, a4 = 10, a5, a6 };int a1; // error!重定義了!上面定義過a1了!enum bb {a2,a4}; // error!
}
4 enum與int
enum中的枚舉成員,都是int類型的變量,也代表int類型的值,值的范圍也是int的范圍。
5 enum與#define
5.1 共同點
下面兩段代碼基本來說是等價的:
#define Working 0
#define Failed 1
#define Freezed 2
enum state {Working, Failed, Freezed};
5.2 enum的優勢
#define是全局的,而enum則是與基本數據類型一樣,范圍非常靈活。
5.3 #define的優勢
enum只能定義int類型值,define什么都可以等價,任何值,以及函數,都可以。
6 enum的大小(size)
6.1 變量的大小
注意:討論enum結構本身大小沒必要,因為其變量,就是這個結構的實例化,這一點和struct一樣的!
enum aa { a1 = 10, a2, a3 };
enum aa abc = a2;
printf("size = %d\n", sizeof(enum aa)); // 4
printf("size = %d\n", sizeof(abc)); // 4
試一下就知到了,都是4字節
。這倆肯定相等,一個是模板,一個是實例。
為什么是4呢?
因為enum這里面的值,其實就是int
類型的,那不就是4嗎!然后這個枚舉變量,值只能有一個吧,那就占一個4字節空間足夠了。
像struct那是可以有多個值,所以每個變量都占空間,這個就沒必要,一堆里面選一個就可以了。
另外就是,不要試圖獲取枚舉成員的地址,因為它有沒有用上場都不一定呢,它只是C語言層級的一個值而已,不一定被分配。
好吧,沒人這么閑的沒事干。
7 奇奇怪怪
enum aa abc = 100;
printf("***%d\n", abc); // 100
這種情況下,就真的當int用了,其實也沒啥,反正編譯器允許,不過一般沒人這么干。
8 最后,說說真正常用的地方
說實話,說了這么多,基本都很少用得到!常用的地方也就固定套路,內些野路子你看看就好。
就比如你定義個月份什么,星期什么的。
#include<stdio.h>enum year{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};int main()
{int i;for (i=Jan; i<=Dec; i++) printf("%d ", i);return 0;
}
另外還有就是,編譯原理中的,詞法分析器的單詞表,需要把編號和名稱對應起來,enum是天然適合的結構,使用struct嵌套enum和其他,就很完美很方便。