c語言之列舉型別(enum)
1 列舉型別
1 。 如果一個變數只有幾種可能的值,則可以定義為“列舉型別”;所謂“列舉”就是把可能的值一一的列舉出來,變數的值只限於列舉出來的值的範圍, 如:
語法:
enum
列舉型別
{
列舉成員列表
};
//其中的列舉成員列表是以逗號“,”相分隔
如:
enum
Spectrum
{
red
,
balck
,
yellow
,
blue
,
white
};
時間:2018-10-24 修改,Spectrum列舉變數中成員
balck
寫錯了,應為
black
。多謝 [福蔥] 讀者的提示!
enum Spectrum{red,balck,yellow,blue,white};
enum
Spectrum
{
red
,
black
,
yellow
,
blue
,
white
};
其中:
enum為關鍵字
,
Spectrum為該列舉型別的標記名
(標記名:遵循識別符號的命名規則);
花括號“
{}
”中的
red
,
black
,
yellow
,
blue
,
white稱為
“列舉元素”或“列舉常量”;
2。可以用“列舉型別”宣告符號名稱來表示int型常量。只要是能使用int型的地方就能夠使用列舉型別。注意:C語言中的列舉的一些特性不適合C++;比如c中的列舉變數允許使用++運算子,但是c++中則不允許。
3。有關列舉型別常量的預設值
這裡仍然拿上面的列舉型別常量作為示例:
enum
Spectrum
{
red
,
black
,
yellow
,
blue
,
white
};
0
1
2
3
4
預設情況下:該列舉列表中的常量值分別為:
0
,
1
,
2
,
3
,
4
當然也可以在列舉宣告中,可以為列舉常量指定整數值:如
enum
Spectrum
{
red
=
10
,
black
=
20
,
yellow
=
30
,
blue
=
40
,
white
=
50
};
也可以只對列舉型別中的一個列舉元素賦值;這時該列舉元素後面的列舉元素會被賦予後續的值。如:
enum
Spectrum
{
red
,
black
=
22
,
yellow
,
blue
,
white
};
則:
red
=
0
,
black
=
22
,
yellow
=
23
,
blue
=
24
,
white
=
25
;
此外,還可在列舉型別成員列表中,宣告多個成員的數值(整型常量值)相同, 如:
enum
Spectrum
{
red
,
black
=
22
,
yellow
,
blue
=
22
,
white
};
則
:
red
=
0
,
black
=
22
,
yellow
=
23
,
blue
=
22
white
=
23。
2018-04-26 07:04:01 補充
4。列舉型別也可以是匿名的
匿名的列舉型別會有著意想不到的作用,比如在程式中需要使用
數值的名字
的時候,常常有
3
種方法可以實現。
(1)宏定義
#define FALSE 0
#define TRUE 1
但是
宏定義
有弱點:其定義的只是預處理階段的名字,在編譯器的預處理階段會進行簡單的名字替換,而且不會進行型別的安全檢查,其作用域是全域性的 href=“
https://
blog。csdn。net/lixiaogan
g_theanswer/article/details/80140522
”>( C++11強列舉型別 ) ,因此若程式中有變數
true、false
,則會被替換。為了避免這樣的情況,採用將全部的宏用
大寫
來命名,以區別於正常的程式碼。
(2)匿名的
enum
列舉
enum
{
FALSE
,
TRUE
};
//FALSE 0, TRUE 1Text only
這裡的
FALSE,TRUE
都是編譯時期的名字,編譯器會對其進行型別檢查,若程式碼中其他地方有和該名字衝突的,會報錯。因此採用匿名的列舉不會有產生干擾正常程式碼的尷尬。
(3)採用靜態變數
C++中更加推薦使用該方式,如:
static
const
int
FALSE
=
0
;
static
const
int
TRUE
=
1
;
在這裡的
TRUE,FALSE
同樣會得到編譯器在編譯階段的檢查。由於是靜態變數,因此其作用域被限制到了本檔案內。相比於
enum
列舉型別,靜態變數不僅是編譯時期的名字,同時編譯器還可能會在程式碼中為
TRUE,FALSE
產生實際的資料,這會增加一點儲存空間。
5。列舉型別的作用:提高程式的可讀性和可維護性
示例程式碼一:輸出12個月的英文單詞
#include
#include
enum
Months
{
jan
=
1
,
feb
,
mar
,
apr
,
may
,
jun
,
jul
,
aug
,
sep
,
oct
,
nov
,
dec
};
int
main
(
void
)
{
enum
Months
m
;
//flag用來標記輸出的個數,若為4個,則輸出一個換行符
int
flag
=
0
;
//指標陣列,存放的是個字串的入口地址
char
*
months
[]
=
{
“January”
,
“February”
,
“March”
,
“April”
,
“May”
,
“June”
,
“July”
,
“August”
,
“September”
,
“October”
,
“November”
,
“December”
};
for
(
m
=
jan
;
m
<=
dec
;
m
++
)
{
printf
(
“%-d月份:%-10s ”
,
m
,
months
[
m
-
1
]);
flag
++
;
if
(
flag
%
4
==
0
)
{
putchar
(
‘\n’
);
}
}
system
(
“pause”
);
return
0
;
}
示例程式碼二:用作函式返回錯誤碼
這是在程式設計中使用得最為廣泛的用法之一,通常在開發中,我們把考慮到的所有可能出現的錯誤都列舉在一個enum中,這樣,我們就不用再函式調用出錯時候,返回一個數字。這樣的做法好處有很多:如更容易看出函式調用出錯的原因、如果enum中有漏掉的錯誤提示,則再新增一個等。
typedef
enum
{
/* Internal errors to rdkafka: */
RD_KAFKA_RESP_ERR__BEGIN
=
-
200
,
/* begin internal error codes */
RD_KAFKA_RESP_ERR__BAD_MSG
=
-
199
,
/* Received message is incorrect */
RD_KAFKA_RESP_ERR__BAD_COMPRESSION
=
-
198
,
/* Bad/unknown compression */
RD_KAFKA_RESP_ERR__DESTROY
=
-
197
,
/* Broker is going away */
RD_KAFKA_RESP_ERR__FAIL
=
-
196
,
/* Generic failure */
RD_KAFKA_RESP_ERR__TRANSPORT
=
-
195
,
/* Broker transport error */
RD_KAFKA_RESP_ERR__CRIT_SYS_RESOURCE
=
-
194
,
/* Critical system resource
* failure */
RD_KAFKA_RESP_ERR__RESOLVE
=
-
193
,
/* Failed to resolve broker */
RD_KAFKA_RESP_ERR__MSG_TIMED_OUT
=
-
192
,
/* Produced message timed out*/
RD_KAFKA_RESP_ERR__PARTITION_EOF
=
-
191
,
/* Reached the end of the
* topic+partition queue on
* the broker。
* Not really an error。 */
RD_KAFKA_RESP_ERR__UNKNOWN_PARTITION
=
-
190
,
/* Permanent:
* Partition does not
* exist in cluster。 */
RD_KAFKA_RESP_ERR__FS
=
-
189
,
/* File or filesystem error */
RD_KAFKA_RESP_ERR__UNKNOWN_TOPIC
=
-
188
,
/* Permanent:
* Topic does not exist
* in cluster。 */
RD_KAFKA_RESP_ERR__ALL_BROKERS_DOWN
=
-
187
,
/* All broker connections
* are down。 */
RD_KAFKA_RESP_ERR__INVALID_ARG
=
-
186
,
/* Invalid argument, or
* invalid configuration */
RD_KAFKA_RESP_ERR__TIMED_OUT
=
-
185
,
/* Operation timed out */
RD_KAFKA_RESP_ERR__QUEUE_FULL
=
-
184
,
/* Queue is full */
RD_KAFKA_RESP_ERR__ISR_INSUFF
=
-
183
,
/* ISR count < required。acks */
RD_KAFKA_RESP_ERR__END
=
-
100
,
/* end internal error codes */
/* Standard Kafka errors: */
RD_KAFKA_RESP_ERR_UNKNOWN
=
-
1
,
RD_KAFKA_RESP_ERR_NO_ERROR
=
0
,
RD_KAFKA_RESP_ERR_OFFSET_OUT_OF_RANGE
=
1
,
RD_KAFKA_RESP_ERR_INVALID_MSG
=
2
,
RD_KAFKA_RESP_ERR_UNKNOWN_TOPIC_OR_PART
=
3
,
RD_KAFKA_RESP_ERR_INVALID_MSG_SIZE
=
4
,
RD_KAFKA_RESP_ERR_LEADER_NOT_AVAILABLE
=
5
,
RD_KAFKA_RESP_ERR_NOT_LEADER_FOR_PARTITION
=
6
,
RD_KAFKA_RESP_ERR_REQUEST_TIMED_OUT
=
7
,
RD_KAFKA_RESP_ERR_BROKER_NOT_AVAILABLE
=
8
,
RD_KAFKA_RESP_ERR_REPLICA_NOT_AVAILABLE
=
9
,
RD_KAFKA_RESP_ERR_MSG_SIZE_TOO_LARGE
=
10
,
RD_KAFKA_RESP_ERR_STALE_CTRL_EPOCH
=
11
,
RD_KAFKA_RESP_ERR_OFFSET_METADATA_TOO_LARGE
=
12
}
rd_kafka_resp_err_t
;
上面的程式碼是 kafka C客戶端中的原始碼,即列舉出kafka 客戶端中可能會出現的錯誤的原因。通常,還會實現2個函式,如:
//1。返回便於人們閱讀的錯誤字串
const
char
*
rd_kafka_err2str
(
rd_kafka_resp_err_t
err
);
//該函式的實現很簡單,即以字串形式列印error,如:
const
char
*
rd_kafka_err2str
(
rd_kafka_resp_err_t
err
)
{
char
*
tempStr
=
NULL
;
//對err的判斷
switch
(
err
)
{
case
RD_KAFKA_RESP_ERR__BEGIN
:
tempStr
=
“RD_KAFKA_RESP_ERR__BEGIN”
;
break
;
//或: case RD_KAFKA_RESP_ERR__BEGIN: return “RD_KAFKA_RESP_ERR__BEGIN”;
//此處省略。。。。。
}
}
//2。若errnox錯誤碼在我們列舉出的enum中,則返回enum中的錯誤碼列印
rd_kafka_resp_err_t
rd_kafka_errno2err
(
int
errnox
);
一般在函式呼叫失敗的地方的日誌列印中,加入上面2個函式:先
rd_kafka_errno2err
,再
rd_kafka_err2str
。
如:
#include
#include
#include
using
namespace
std
;
enum
{
OPERATOR_OK
=
0
,
//成功
OPERATOR_ERR
=
1
,
//失敗
MALLOC_MEMORY_ERR
=
2
,
//申請記憶體空間失敗
FUNCTION_PARAM_NULL
=
3
,
//函式引數為空
FUNCTION_PARAM_ERR
=
4
//函式引數錯誤
//省略……
};
/**@fn Div
* @brief 除法函式
* @param[in] const int a 被除數
* @param[in] const int b 除數
* @param[out] int &outData 結果值
* @return int
**/
int
Div
(
const
int
a
,
const
int
b
,
int
&
outData
)
{
if
(
b
<=
0
)
{
fprintf
(
stderr
,
“Div param is err。”
);
return
FUNCTION_PARAM_ERR
;
}
outData
=
a
/
b
;
return
OPERATOR_OK
;
}
/**@fn err2str
* @brief 將錯誤碼轉換為對應字串
* @param[out] const int ierrno 待轉換的錯誤碼
* @return 轉換後的錯誤碼字串
**/
const
char
*
err2str
(
const
int
ierrno
)
{
if
(
OPERATOR_OK
>
ierrno
||
ierrno
>
FUNCTION_PARAM_ERR
)
{
puts
(
“err2str param is err。”
);
return
NULL
;
}
switch
(
ierrno
)
{
case
OPERATOR_OK
:
return
“OPERATOR_OK”
;
break
;
case
OPERATOR_ERR
:
return
“OPERATOR_ERR”
;
break
;
case
MALLOC_MEMORY_ERR
:
return
“MALLOC_MEMORY_ERR”
;
break
;
case
FUNCTION_PARAM_NULL
:
return
“FUNCTION_PARAM_NULL”
;
break
;
case
FUNCTION_PARAM_ERR
:
return
“FUNCTION_PARAM_ERR”
;
break
;
default
:
return
NULL
;
break
;
}
}
int
main
()
{
int
a
=
6
,
b
=
2
;
int
iResult
=
0
;
if
(
OPERATOR_OK
!=
Div
(
a
,
b
,
iResult
))
{
printf
(
“Div failed[%d]-[%s]
\n
”
,
Div
(
a
,
b
,
iResult
),
err2str
(
Div
(
a
,
b
,
iResult
)));
return
-
1
;
}
std
::
cout
<<
“Div: ”
<<
iResult
<<
std
::
endl
;
return
0
;
}
列印結果
Div
:
3
更多有關“
計算機原理&編譯原理、C/C++、PostgreSQL、資料結構&演算法等
”的技術文章將第一時間更新於公眾號:[
雅俗不共賞
]。