2012-02-29 38 views

回答

8

沒有完全一般的解決方案。枚舉代​​表性條款似乎旨在使這些信息難以獲得。

此:

function Rep is new Ada.Unchecked_Conversion(Enum, Integer); 

很可能在大多數情況下工作,但也有一些嚴重的警告:代表值必須在該範圍內Integer'First..Integer'Last,而如果EnumInteger大小不匹配的結果實際上是實現定義的(但它適用於GNAT)。

正如西蒙賴特所說,RM建議Unchecked_Conversion,但這不是一個非常令人滿意的解決方案,並且確定一致的目標類型是困難的。

作爲2007 RM的,支持的推薦的等級爲:

實現應該支持至少在 範圍System.Min_Int..System.Max_Int內部碼。

這意味着轉換爲Integer並不總是足夠的;值可能小於Integer'First,或大於Integer'Last。即使所有值都在該範圍內,但確定與枚舉類型大小相同的目標類型並沒有真正的好方法。例如,這樣的:

type Enum is (Ten, Twenty, Thirty); 
for Enum use (10, 20, 30); 
function Rep is new Ada.Unchecked_Conversion(Enum, Integer); 

在GNAT產生這樣的警告:

warning: types for unchecked conversion have different sizes 

但警告之後,代表人員返回預期值分別爲10,20和30。

將RM明確地指出,如果在無檢查的一個實例的源和目標的大小不匹配,並且將結果的類型是標量,然後

函數的結果被實現定義的,並且可以有一個 無效表示

所以,上述工作對於GNAT的事實並不意味着它保證在任何地方工作。

對於支持範圍System.Min_Int..System.Max_Int價值的實現,你可以做這樣的事情:

type Enum is (...); 
for Enum use (...); 
type Longest_Integer is range System.Min_Int .. System.Max_Int; 
function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Integer); 

,並忽略警告。但編譯器允許允許接受大於System.Max_Int的值,只要它們在某個整數類型的範圍內。例如,GNAT拒絕這一點,但其他Ada編譯可能會接受它:

type Longest_Unsigned is mod System.Max_Binary_Modulus; 
type Unsigned_Enum is (Zero, Huge); 
for Unsigned_Enum use (0, Longest_Unsigned'Last); 

,並從這樣的一個檢查轉換到任何符號整型將無法正常工作。如果尺寸不匹配,您仍然有實現定義結果的潛在問題。

這裏的一個通用的解決方案應該針對任何枚舉類型工作,如果(a)中表示的值的範圍是System.Min_Int..System.Max_Int,和(b)如果Unchecked_Conversion實現是更好的表現比阿達標準要求它:

type Longest_Signed is range System.Min_Int .. System.Max_Int; 

generic 
    type Enum is (<>); 
function Generic_Rep(E: Enum) return Longest_Signed; 

function Generic_Rep(E: Enum) return Longest_Signed is 
    function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Signed); 
begin 
    return Rep(E); 
end Generic_Rep; 

考慮到所有這些困惑,您可能會考慮使用枚舉表達式子句以外的某種機制來做任何您想要做的事情。

+0

非常好,內容翔實的答案! – oenone 2012-03-01 08:08:18

+0

優秀的答案。不要忘記,你也可以做相反的事(int枚舉),並檢查有效性'有效! – NWS 2012-03-01 08:48:00

+0

非常好的答案。請注意:如果您創建新的整數類型,則可以避免「不同大小」警告,併爲Enum和整數指定相同的Size屬性。 'type Unsigned_Byte是新的自然範圍0 .. 255;用於Unsigned_Byte'Size的 使用8; \t Enum'Size使用8;'' – 2013-09-02 08:31:59

2

AARM 13.4(第11/1段)推薦Unchecked_Conversion(可能是Integer)。

5

如果您使用的是GNAT,並且不介意編譯器特定,那麼編譯器會爲此提供Enum_Rep屬性。

1

如果你不使用JVM或.NET編譯器,你可以覆蓋這兩個;像這樣:

Value : Integer; 
For Value'Address use ENUM_VAR'Address; 

你會想要使用抑制初始化的雜注,雖然我現在不記得它。

IIRC,還有變型記錄方法,您可以在其中準確疊加字段並將記錄用作視圖轉換類型。

+1

'編譯導入(Value,Ada);',我想。 – 2012-02-29 21:07:43

+0

我認爲這可能是。 – Shark8 2012-03-01 00:42:49

+0

如果要在枚舉頂部覆蓋數字項目,則應確保實例大小相同。 – 2012-03-01 01:38:01

1

正如我所瞭解的質量和風格指南,不應該照顧枚舉的內在表示值。大量的研究後,有一次我決定使用下面的結構:

type enum_c is (clk_eq, clk_div_2, clk_div_16, clk_div_128, clk_div_1024); 

type enum_c_values is array (enum_c) of natural; -- or any type you wish 

cdiv_values : constant enum_c_values := (
    clk_eq   => 1, 
    clk_div_2  => 2, 
    clk_div_16  => 16, 
    clk_div_128 => 128, 
    clk_div_1024 => 1024); 

c : enum_c := clk_div_128; 
... 
put_line("c =" & c'img & " natural value associated w/ c =" & cdiv_values(c)'img); 
0

我找到了在GNAT工作是:

type MyEnum is (A, B, C); 

我不得不這樣做:

EVal : MyEnum := B; 
IVal : Integer := MyEnum'Enum_Rep(EVal);