我只負責轉換![C/C++]
Written by Allen Lee
前不久,lsp在這裡留下這樣一個問題:
說明:
1.定義了一個枚舉如下:
enum _jb_prog_mode
{
PROGRAM_ONE = 0,
PROGRAM_TWO
};
enum _jb_prog_mode e_prog_index;
2.疑惑:
e_prog_index = (enum _jb_prog_mode)-1;
e_prog_index等於-1?為什嗎?
你的疑惑隱藏著這樣一個結論:e_prog_index的值不應該等於-1。我相信你得出這個結論的理由是_jb_prog_mode枚舉中沒有哪個成員的值為-1,於是類型為_jb_prog_mode的變數e_prog_index的值也不應該為-1。
現在,我們轉換一下情境,假定註冊表中有如下的資訊:
[HKEY_LOCAL_MACHINE\SOFTWARE\Allen]
"Name"="Allen Lee"
"ID"=dword:00000584
我們如何通過編程擷取這些資訊呢?我們可以使用Win32 API的RegQueryValueEx()函數來讀取這些資訊(代碼片斷):
LPBYTE lpData;
DWORD dataBufLen;
if (RegQueryValueEx(hKey, // hKey為指向HKEY_LOCAL_MACHINE\SOFTWARE\Allen的控制代碼
"Name",
NULL,
NULL,
lpData,
&dataBufLen) == ERROR_SUCCESS)
{
// Convert_01:
char* data = new char[dataBufLen];
data = (char*)lpData;
std::cout "User name: " data std::endl;
// Convert_02:
// DWORD* data = (DWORD*)lpData;
// std::cout
}
if (RegQueryValueEx(hKey,
"ID",
NULL,
NULL,
lpData,
&dataBufLen) == ERROR_SUCCESS)
{
// Convert_03:
DWORD* data = (DWORD*)lpData;
std::cout "User ID: " *data std::endl;
// Convert_04:
// char* data = new char[dataBufLen];
// char* data = (char*)lpData;
// std::cout
}
留意這段代碼有兩次轉換,如果我們分別把Convert_01和Convert_03替換為Convert_02和Convert_04的話會怎麼樣呢?編譯器不會為難你的,但運行效果可想而知。
回顧這兩個例子,我們可以得到什麼結論呢?正如本文的題目——
我只負責轉換!
當你強制把-1轉換為_jb_prog_mode類型並賦值予e_prog_index變數時,你只能說e_prog_index變數不包含_jb_prog_mode枚舉預定義的值,並不能說e_prog_index變數的值非法(其實枚舉類型和整數類型之間有著很深的淵源)。編譯器是不會妨礙你的這種轉換,而這種轉換是否有意義就是另外一回事了。當然,你應該採取某些措施來檢測枚舉變數是否包含預定義的值,否則你將可能不時收到意外驚喜。
在C/C++中,枚舉其實是整數常量的一種表現形式,它實質上只是協助程式員標識一組相關的整數常量。語義上,
enum _jb_prog_mode
{
PROGRAM_ONE = 0,
PROGRAM_TWO
};
等效於
static const int PROGRAM_ONE = 0;
static const int PROGRAM_TWO = 1;
C/C++給予程式員最大的自由來進行選擇,這也體現出C/C++對程式員的信任。然而,這種信任究竟是協助我們還是傷害我們,就要看程式員本身的做法了。
最後,我引用Robert B. Murray的一段話[1]結束本文:
寫出依賴於語言中定義含糊、意義微妙的規則的程式是不好的,即便作者本人清楚它的意義並保證它可以正確運行,下一個來維護這段代碼的人也可能未必能夠做到這點。比較好的做法是:堅持使用語言中那些被廣泛使用及理解的部分來寫程式。
See also:
- Allen Lee;《關於枚舉的種種 (Enumeration FAQ) [C#, IL, BCL]》
- Allen Lee;《我並不是不聞不問![C#]》
- [1] [美]Robert B. Murray 著;王昕 譯;《C++ 編程慣用法——進階程式員常用方法和技巧》;中國電力出版社,2004