讀K&R的The C Programmingh Language 2nd,遇到一疑問,書中說:“盡管可以聲明enum類型的變量,但編譯器不檢查這種類型的變量中存儲的值是否為該枚舉的有效值。不過,枚舉變量提供這種檢查,因此枚舉比#define更具優勢。”
枚舉變量提供這種檢查,什么意思?枚舉變量會自己檢?當然不是,作者也許想說程序員自己可以寫個程序檢查付給枚舉變量的值是否為該枚舉的有效值。
/* 包含頭文件 */
#include <stdio.h>
/* 枚舉類型 */
enum months{JAN = 1, FEB};
/* 函數原型 */
void enumeration(enum months m);
main()
{
enum months a = 2;
enum months b = 50; /* C中不需要強制轉換為enum months類型 */
enum months c = JAN;
enumeration(a);
enumeration(b);
return 0;
}
/* enumeration函數:檢測枚舉變量存儲的值是否為該枚舉的有效值 */
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++源文件編譯,卻不能通過。原因如下:
根據C標準的規定,枚舉常量的類型為int,枚舉變量的類型應該與char、有符號或無符號整型兼容。因此,枚舉變量可以接受 char、有符號或無符號整型數,而不限于僅從此枚舉類型所定義的枚舉常量中取值。由于上述原因,在C語言中無法從語法上保證枚舉變量只能在定義的枚舉成員中取值,只能由程序員自身保證不使用除枚舉成員之外的值。
關于這一點,很多介紹C語言的書上或者資料上的描述是不正確的,應該加以注意。
但是,如果給枚舉變量賦枚舉成員之外的值,有的編譯器可能會對此產生警告,有的則不會。因為這種行為不違反C標準的規定,編譯器對此如何反應都是有道理的。
然而對于C++來說,編譯器會禁止給枚舉變量賦予枚舉成員之外的值。這是因為C++是一種強類型語言,枚舉類型不等同于 int 等其它類型。雖然枚舉類型可以隱式轉化為 int 等類型,但是 int 等類型卻不能自動轉化為枚舉類型,除非使用強制類型轉化。因此,如果不使用強制類型轉化的話,給枚舉變量賦值則只能從枚舉成員中選擇。對于枚舉類型要避免使用強制類型轉換。原因如下:
The C++ Programming Language上說:
如果某個枚舉中所有枚舉值非負,枚舉的表示范圍為[0 : 2^k-1];其中2^K是使所有枚舉成員位于此范圍內的最小的2的冪;如果是負的,就是[-2^k : 2^k-1]。 因此對一個給定的整數值,如果使用強制類型轉換,而其值又不在枚舉的表示范圍以內,其行為是未定義的。
// 包含頭文件
#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,但結果是未定義的,因為此枚舉的表示范圍為:0~3
return 0;
}