讀K&R的The C Programmingh Language 2nd,遇到一疑問(wèn),書(shū)中說(shuō):“盡管可以聲明enum類(lèi)型的變量,但編譯器不檢查這種類(lèi)型的變量中存儲(chǔ)的值是否為該枚舉的有效值。不過(guò),枚舉變量提供這種檢查,因此枚舉比#define更具優(yōu)勢(shì)。”
枚舉變量提供這種檢查,什么意思?枚舉變量會(huì)自己檢?當(dāng)然不是,作者也許想說(shuō)程序員自己可以寫(xiě)個(gè)程序檢查付給枚舉變量的值是否為該枚舉的有效值。
/* 包含頭文件 */
#include <stdio.h>
/* 枚舉類(lèi)型 */
enum months{JAN = 1, FEB};
/* 函數(shù)原型 */
void enumeration(enum months m);
main()
{
enum months a = 2;
enum months b = 50; /* C中不需要強(qiáng)制轉(zhuǎn)換為enum months類(lèi)型 */
enum months c = JAN;
enumeration(a);
enumeration(b);
return 0;
}
/* enumeration函數(shù):檢測(cè)枚舉變量存儲(chǔ)的值是否為該枚舉的有效值 */
void enumeration(enum months m)
{
switch (m)
{
case JAN:
printf("JAN: %d\n", JAN);
break;
case FEB:
printf("FEB: %d\n", FEB);
break;
default:
printf("%d不是該枚舉的有效值!\n", m);
break;
}
}
而這段代碼如果改為C++源文件編譯,卻不能通過(guò)。原因如下:
根據(jù)C標(biāo)準(zhǔn)的規(guī)定,枚舉常量的類(lèi)型為int,枚舉變量的類(lèi)型應(yīng)該與char、有符號(hào)或無(wú)符號(hào)整型兼容。因此,枚舉變量可以接受 char、有符號(hào)或無(wú)符號(hào)整型數(shù),而不限于僅從此枚舉類(lèi)型所定義的枚舉常量中取值。由于上述原因,在C語(yǔ)言中無(wú)法從語(yǔ)法上保證枚舉變量只能在定義的枚舉成員中取值,只能由程序員自身保證不使用除枚舉成員之外的值。
關(guān)于這一點(diǎn),很多介紹C語(yǔ)言的書(shū)上或者資料上的描述是不正確的,應(yīng)該加以注意。
但是,如果給枚舉變量賦枚舉成員之外的值,有的編譯器可能會(huì)對(duì)此產(chǎn)生警告,有的則不會(huì)。因?yàn)檫@種行為不違反C標(biāo)準(zhǔn)的規(guī)定,編譯器對(duì)此如何反應(yīng)都是有道理的。
然而對(duì)于C++來(lái)說(shuō),編譯器會(huì)禁止給枚舉變量賦予枚舉成員之外的值。這是因?yàn)镃++是一種強(qiáng)類(lèi)型語(yǔ)言,枚舉類(lèi)型不等同于 int 等其它類(lèi)型。雖然枚舉類(lèi)型可以隱式轉(zhuǎn)化為 int 等類(lèi)型,但是 int 等類(lèi)型卻不能自動(dòng)轉(zhuǎn)化為枚舉類(lèi)型,除非使用強(qiáng)制類(lèi)型轉(zhuǎn)化。因此,如果不使用強(qiáng)制類(lèi)型轉(zhuǎn)化的話(huà),給枚舉變量賦值則只能從枚舉成員中選擇。對(duì)于枚舉類(lèi)型要避免使用強(qiáng)制類(lèi)型轉(zhuǎn)換。原因如下:
The C++ Programming Language上說(shuō):
如果某個(gè)枚舉中所有枚舉值非負(fù),枚舉的表示范圍為[0 : 2^k-1];其中2^K是使所有枚舉成員位于此范圍內(nèi)的最小的2的冪;如果是負(fù)的,就是[-2^k : 2^k-1]。 因此對(duì)一個(gè)給定的整數(shù)值,如果使用強(qiáng)制類(lèi)型轉(zhuǎn)換,而其值又不在枚舉的表示范圍以?xún)?nèi),其行為是未定義的。
// 包含頭文件
#include <iostream.h>
int main()
{
enum months{JAN = 1, FEB, MAR};
//enum months a = 1; //cannot convert from 'const int' to 'enum main::months'
enum months a = (enum months)1;
cout << "a: " << a << endl; //輸出: a: 1
enum months b = (enum months)10;
cout << "b: " << b << endl; //輸出: b: 10 雖然輸出10,但結(jié)果是未定義的,因?yàn)榇嗣杜e的表示范圍為:0~3
return 0;
}