enum型用於定義常量集合,相比#define有一些優勢,如:enum是一種資料型別,使用時會檢查型別匹配;enum增加了範圍約束,避免變數賦值和使用時超出定義範圍。但enum也有乙個隱含問題:enum變數占用的空間與編譯器相關。
多數編譯器預設enum型長度等於int型,很多人也把enum型變數等同於int,但c標準在這裡留下了尾巴:「列舉型尺寸是能夠容納最大枚舉子值的整數尺寸」,「列舉型別中枚舉子的值必須要能用乙個int型表述」。也就是說,列舉型的尺寸不能超過int型,但不必等於int型,只要能容納最大枚舉子就行,下例:
enum etype1 ;
enum etype2 ;
這兩個列舉型別最小可用char、short的記憶體空間表示,即有可能:
sizeof( etype1 ) == sizeof( char );
sizeof( etype2 ) == sizeof( short );
一些編譯器為節約記憶體可以設定這種「量體裁衣」的策略。如ads就有圖示選項(enum container always int),選定後enum變數長度為int,否則就等於能容納最大枚舉子的最短長度。gcc也有類似選項-fshort-enums,預設不設定,一旦設定就選用節省記憶體的enum長度。
enum長度不確定會帶來可移植性問題,如果第三方庫api介面使用enum型別,編譯和呼叫庫時一旦有關enum長度的編譯器設定不一致,api介面層對數值的解析就不匹配。比如上層應用編譯時沒有用-fshort-enums,預設用4位元組空間來儲存使用enum變數,而編譯庫時設定了fshort-enums,則庫內部此enum size可能為1。當把enum變數位址傳進api時,內部只修改變數最低位元組,高3位元組值無變化(內容隨機),api返回時,上層使用的4位元組enum變數值就可能隨機。(潛規則篇之api介面)
因此內部**使用enum型別優於define,但對外api介面盡量避免用enum型。
在用keil做關於stm32的專案時,就碰到這樣的的問題,可以通過設定列舉變數為固定int型別來保證與上位機的一致。
C陷阱篇之enum預設長度
僅用於學習 enum型用於定義常量集合,相比 define有一些優勢,如 enum是一種資料型別,使用時會檢查型別匹配 enum增加了範圍約束,避免變數賦值和使用時超出定義範圍。但enum也有乙個隱含問題 enum變數占用的空間與編譯器相關。多數編譯器預設enum型長度等於int型,很多人也把enu...
C陷阱篇之常見手誤
c的某些語法容易讓人不小心觸雷,比如 從0開始的下標 很多高階語言中,定義n個元素的陣列,下標範圍是從1到n,但c特殊,n元素的c陣列中沒有下標為n的元素,只有從0到n 1的下標。所以使用c陣列時不要犯這種錯誤 int i,a 10 for i 1 i 10 i i 10時超出陣列邊界 八進位制or...
C陷阱篇之常見手誤
c的某些語法容易讓人不小心觸雷 很多高階語言中,定義n個元素的陣列,下標範圍是從1到n,但c特殊,n元素的c陣列中沒有下標為n的元素,只有從0到n 1的下標。所以使用c陣列時不要犯這種錯誤 int i,a 10 for i 1 i 10 i i 10時超出陣列邊界 八進位制or十進位制常數 c編譯器...