2010-08-08 125 views
3

以下是我們的代碼庫中的典型情況。scanf()與C++枚舉

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 } 

ConfigOption cfg1, cfg2; 

sscanf(s, "%d", &cfg1); 

這是一個內部使用的仿真軟件。未分配。易於維護和正確性非常重要。可移植性和用戶界面 - 不是真的。

問題是在C++中enum不一定是int。所以我們得到一個編譯器警告,並且在使用不同的編譯器或啓用優化時可能會得到不正確的行爲。

一種解決方案是將&cfg投射到int*。但是,這並不能解決編譯器決定將int以外的內容分配給enum的情況。

所以我建議採取以下解決辦法:

template<typename T> inline 
int& eint(T& enum_var) { 
    assert(sizeof(T) == sizeof(int)); 
    return (int&)enum_var; 
} 

現在一個使用scanf如下:

sscanf(s, "%d", &eint(cfg1)); 

我很願意聽取意見和其他(更好的)解決方案的上述問題。請記住,其中一個目標是保持代碼簡單。這不是'生產質量'的東西,你添加得越多 - 維護就越困難。

+1

在編譯時,我會建議一個靜態(編譯時)斷言(例如'BOOST_STATIC_ASSERT'),所以如果大小不正確,你會得到一個* compiler *錯誤。如果你這樣做,你可以找到有問題的枚舉,並使用下面的Nils的建議來修復它。 – UncleBens 2010-08-08 09:51:14

回答

4

如果你有一個現代化的編譯器像VS2010你可以指定大小枚舉元素

enum class ConfigOption: unsigned int {CONFIG_1=1, CONFIG_2=2, CONFIG_3=3}; 

其新的C++ 0x中的

+0

酷!很好的功能。 – 2010-08-08 08:12:20

+0

不幸的是,我們仍然使用舊版本的gcc。不過,這似乎是最乾淨的解決方案,所以我會接受它。 – nimrodm 2010-08-09 06:50:02

0

您可以嘗試使用boost::lexical_cast,或者如果您沒有使用boost並且不想在此情況下開始使用它,則可以自己編寫一個簡化版本。舉個例子看看at this SO answer

+0

'boost :: lexical_cast'依靠流操作符''重載''。只有當這些運算符對這個枚舉超載時,它才能與枚舉一起工作。 – UncleBens 2010-08-08 10:06:24

2

我的解決方案是強制將枚舉強制爲最小大小。這就是微軟在其DirectX頭文件中所做的枚​​舉(這是我不得不承認的一個很好的技巧)。

他們執行的枚舉的大小等於一個int加上空枚舉這樣的:

typedef enum 
{ 
    fooo = 1, 
    baar = 2, 
    ___Force32Bit = ~0UL 
} MyEnum; 

現在枚舉總是會至少 int的大小。

如果你願意,你可以藉此在上面。這一個強制枚舉的大小,很長很長:

typedef enum 
{ 
    fooo = 1, 
    baar = 2, 
    ___Force64Bit = ~0ULL 
} MyEnum; 

我知道,這是不是一個超級乾淨的解決方案。我認爲這樣的解決方案不存在,並且迄今爲止執行的最小尺寸對我來說效果很好。如果你使用32位到64位的代碼,你可能需要調整代碼,但通常在這種情況下,你必須重新查看代碼的某些部分,所以沒有大問題。

順便說一句 - 對不起的C代碼,我知道這個問題是標記爲C++,但我是一個C-傢伙:-)

1

爲什麼不直接讀取它作爲實際int

enum ConfigOption { CONFIG_1=1, CONFIG_2=2, CONFIG_3=3 }; 
ConfigOption cfg1; 

int i; 
sscanf(s, "%d", &i); 
cfg1 = i; 

而且這樣你可以做更全面的有效性檢查過(如測試所讀取的整數是你enum類型的範圍內)。

由於`的sizeof(T)`評估(當然,如果你在所有關心檢測錯誤,對於簡單的解析這個樣子,你應該使用strtolstrtoul代替sscanf

+0

正確,但令人討厭(你仍然需要一個演員陣容)。我們有這些噸... – nimrodm 2010-08-09 06:48:05