2017-04-01 126 views
1

在我正在閱讀的一本教科書中聲明「雖然在編譯時檢查類型是否兼容,但子範圍需要運行時範圍檢查。」 如果我得到正確的結果,則必須在將新值分配給在特定子範圍(子類型)中定義的變量時執行運行時檢查。類型不一樣嗎?爲什麼這個區別?這只是編譯器的默認值?類型檢查和範圍檢查

+0

你在說什麼語言? –

+0

它適用於Ada,也可能適用於其他語言。 –

+1

當你說「subrange check」時,你的意思是檢查在收集元素(如數組)時特定索引是否在允許範圍內?或者它有什麼不同? – oldbam

回答

7

的確如此,從類型U的子類型P分配將不需要檢查,因爲不會有失配(即使子類型與該類型具有相同的範圍; subtype P is U;是完全合法的,並且可以是有用!)

另一種方式,從類型到子類型,將涉及檢查,至少如果子類型是子範圍。

從外部看,另一種不同範圍的類型也是如此。但是,有一個微妙的差異,使用類型/子類型,您可以在不進行轉換的情況下將一個轉換爲另一個,如果不是沒有轉換,但是對於類型/類型,您必須在轉換之前進行類型轉換,並且將在轉換時檢查違反約束的條件,而不是轉讓。

這可能有助於說明這一點:

procedure Drimades is 
    type Upper is range 10 .. 20; 
    subtype Part is Upper range 10 .. 15; 
    type Lower is new Upper range 10 .. 15; 

    procedure Assign_U_To_P (U : Upper; To : out Part) is 
    begin 
     To := U; -- requires check 
    end Assign_U_To_P; 

    procedure Assign_P_To_U (P : Part; To : out Upper) is 
    begin 
     To := P; -- no check needed 
    end Assign_P_To_U; 

    procedure Assign_U_To_L (U : Upper; To : out Lower) is 
    begin 
     To := Lower (U); -- requires check 
    end Assign_U_To_L; 

    procedure Assign_L_To_U (L : Lower; To : out Upper) is 
    begin 
    To := Upper (L); -- no check required 
    end Assign_L_To_U; 

    U : Upper; 
    P : Part; 
    L : Lower; 
begin 
    Assign_U_To_P (20, P); 
    Assign_P_To_U (15, U); 
    Assign_U_To_L (20, L); 
    Assign_L_To_U (15, U); 
end Drimades; 

與GNAT和-gnatG產生這種中間表示,不要太用力,解釋我希望開關編譯如下:

procedure drimades is 
    type drimades__upper is range 10 .. 20; 
    [type drimades__TupperB is new short_short_integer] 
    freeze drimades__TupperB [] 
    subtype drimades__part is drimades__upper range 10 .. 15; 
    [type drimades__TlowerB is new drimades__TupperB] 
    freeze drimades__TlowerB [] 
    type drimades__lower is new drimades__upper range 10 .. 15; 

    procedure drimades__assign_u_to_p (u : drimades__upper; to : out 
    drimades__part) is 
    begin 
     [constraint_error when 
     not (u in 10 .. 15) 
     "range check failed"] 
     to := u; 
     return; 
    end drimades__assign_u_to_p; 

    procedure drimades__assign_p_to_u (p : drimades__part; to : out 
    drimades__upper) is 
    begin 
     to := p; 
     return; 
    end drimades__assign_p_to_u; 

    procedure drimades__assign_u_to_l (u : drimades__upper; to : out 
    drimades__lower) is 
    begin 
     [constraint_error when 
     not (u in 10 .. 15) 
     "range check failed"] 
     to := drimades__lower(u); 
     return; 
    end drimades__assign_u_to_l; 

    procedure drimades__assign_l_to_u (l : drimades__lower; to : out 
    drimades__upper) is 
    begin 
     to := drimades__upper(l); 
     return; 
    end drimades__assign_l_to_u; 

    u : drimades__upper; 
    p : drimades__part; 
    l : drimades__lower; 
begin 
    drimades__assign_u_to_p (20, p); 
    drimades__assign_p_to_u (15, u); 
    drimades__assign_u_to_l (20, l); 
    drimades__assign_l_to_u (15, u); 
    return; 
end drimades; 
2

Simon Wright's answer地址從Ada及其亞型的角度提問,這意味着子集中的某個值,因此不是Ada或C++所稱的派生的類型派生的類別,分別。 (LowerUpper ... ;使得Lower衍生Upper,則所創建的子類型的「...」限定進一步的特徵。)

更一般地,一些語言允許任何變量名在運行時引用任何類型的對象。因此,在JavaScript中,

var a = 15, b = -1; 
    ... 
a = {"foo": "bar"} 
    ... 
return a + b; 

將返回可能令人驚訝的結果,但如果通過語言判斷則結果很好。 a在第二行上被賦予不同類型的新值,並且+將在第三行上產生來自ab的東西。

在Ada,C或Swift等語言中,並不需要這種靈活性:用這種語言編寫的程序可以在任何計算機設備上運行,這意味着不會像字典一樣在一個位置對象聲明是一些整數類型,說。編譯時間類型檢查可以防止這種情況。在分配(或傳遞)對象時需要在編譯時檢測到任何「不尊重」。

除編譯時類型檢查外,Ada還使用基於名稱的類型等價。所以,

type Apples is range 0 .. 20; 
type Oranges is range 0 .. 20; 

a : Apples := 5; 
b : Oranges := 8; 

return a + b; -- Error! 

你得到

8. return a + b; -- Error! 
       | 
    >>> invalid operand types for operator "+" 
    >>> left operand has type "Apples" defined at line 2 
    >>> right operand has type "Oranges" defined at line 3 

這是純粹的類型,在編譯時檢查。最後,擴展Simon Wright的例子說明的內容,有時Ada甚至要求在編譯時檢查子類型。然後涉及的短語是靜態匹配,其中靜態意味着編譯時。例如,相同的邊界。但是,這是先進的東西發生,例如,當指針指向堆棧上的對象,並且這些指針具有與指針不同的範圍(子類型)時。