2012-02-29 34 views

Trả lời

8

Không có giải pháp hoàn toàn chung. Các mệnh đề biểu diễn liệt kê dường như được thiết kế để làm cho thông tin này khó có được.

này:

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

có khả năng làm việc trong hầu hết các trường hợp, nhưng có một số hãy cẩn thận nghiêm trọng: các giá trị đại diện phải trong phạm vi Integer'First..Integer'Last, và nếu các kích thước của EnumInteger không phù hợp với kết quả thực sự được thực hiện được xác định (nhưng nó hoạt động với GNAT).

Như Simon Wright nói, RM khuyến cáo Unchecked_Conversion, nhưng đây không phải là một giải pháp rất thỏa mãn và việc xác định loại mục tiêu nhất quán là khó khăn.

Tính đến RM 2007, mức đề nghị hỗ trợ là:

Một thực hiện, nếu hỗ trợ ít nhất các mã nội bộ trong System.Min_Int..System.Max_Int phạm vi.

có nghĩa là chuyển đổi thành Integer không phải lúc nào cũng đủ; một giá trị có thể nhỏ hơn Integer'First hoặc lớn hơn Integer'Last. Và ngay cả khi tất cả các giá trị nằm trong phạm vi đó, không có cách nào thực sự tốt để xác định loại mục tiêu có cùng kích thước với loại điều tra. Ví dụ, điều này:

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

sản xuất cảnh báo này trong GNAT:

warning: types for unchecked conversion have different sizes 

Nhưng sau khi cảnh báo, Đại diện không trả lại giá trị dự kiến ​​10, 20, và 30.

Các RM một cách rõ ràng rằng nếu nguồn và mục tiêu kích thước trong một thể hiện của Unchecked_Conversion không phù hợp, và loại kết quả là vô hướng, sau đó

kết quả của hàm được thực hiện xác định, và có thể có đại diện không hợp lệ

Vì vậy, thực tế là các công việc trên cho GNAT không có nghĩa là nó được đảm bảo hoạt động ở mọi nơi.

Đối với thực hiện điều đó chỉ hỗ trợ giá trị trong phạm vi System.Min_Int..System.Max_Int, bạn có thể làm một cái gì đó như thế này:

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); 

và bỏ qua những cảnh báo. Nhưng các trình biên dịch được phép cho phép chấp nhận các giá trị lớn hơn System.Max_Int, miễn là chúng nằm trong phạm vi của một số loại số nguyên. Ví dụ: GNAT từ chối điều này, nhưng một trình biên dịch Ada khác có thể chấp nhận nó:

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

và Bỏ chọn_Conversion từ này sang bất kỳ loại số nguyên đã ký nào sẽ không hoạt động. Và bạn vẫn có vấn đề tiềm năng khi triển khai kết quả được xác định nếu kích thước không khớp.

Dưới đây là một giải pháp chung chung mà nên làm việc cho bất kỳ kiểu enumeration nếu (a) các giá trị đại diện nằm trong khoảng System.Min_Int..System.Max_Int, và (b) Nếu việc thực hiện Unchecked_Conversion là cư xử tốt hơn so với tiêu chuẩn Ada đòi hỏi nó phải :

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; 

Cho tất cả sự nhầm lẫn này, bạn có thể xem xét sử dụng một số cơ chế khác với mệnh đề biểu diễn liệt kê để làm bất cứ điều gì bạn đang cố gắng làm.

+0

câu trả lời rất hay và có nhiều thông tin! – oenone

+0

Câu trả lời xuất sắc. Đừng quên, bạn cũng có thể làm ngược lại (int để enum) và kiểm tra tính hợp lệ với 'hợp lệ! – NWS

+0

Câu trả lời rất hay. Lưu ý: bạn có thể tránh cảnh báo "các kích thước khác nhau" nếu bạn tạo một loại số nguyên mới và chỉ định cùng một thuộc tính Kích thước cho cả Enum và số nguyên. 'loại Unsigned_Byte là phạm vi tự nhiên mới 0 .. 255; cho Unsigned_Byte'size sử dụng 8; \t cho Enum'Size sử dụng 8; ' –

2

AARM 13.4 (para 11/1) đề xuất Unchecked_Conversion (đến, có thể, Số nguyên).

5

Nếu bạn đang sử dụng GNAT, và đừng bận tâm đến trình biên dịch cụ thể, trình biên dịch cung cấp thuộc tính Enum_Rep cho mục đích này.

1

Nếu bạn không sử dụng trình biên dịch JVM hoặc .NET, bạn có thể chồng lên hai; một cái gì đó như:

Bạn sẽ muốn sử dụng pragma ngăn chặn khởi tạo, mặc dù tôi không nhớ nó lúc này.

IIRC, Cũng có phương pháp ghi phiên bản, nơi bạn có thể che phủ các trường chính xác và sử dụng bản ghi dưới dạng một loại chuyển đổi chế độ xem.

+1

'pragma Nhập (Giá trị, Ada); ', tôi nghĩ vậy. –

+0

Tôi nghĩ rằng có thể là nó. – Shark8

+0

Nếu bạn sắp xếp một mục số ở trên một điều tra, bạn nên đảm bảo rằng các kích thước cá thể giống nhau. –

1

vì tôi hiểu hướng dẫn về chất lượng và phong cách, người ta không nên quan tâm đến các giá trị đại diện bên trong của liệt kê. sau rất nhiều nghiên cứu, tôi một lần quyết định sử dụng các cấu trúc sau đây:

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

Những gì tôi thấy làm việc trong GNAT dành cho:

type MyEnum is (A, B, C); 

tôi phải làm:

EVal : MyEnum := B; 
IVal : Integer := MyEnum'Enum_Rep(EVal); 
Các vấn đề liên quan