2016-05-31 17 views
1

Im Beispiel unten frage ich mich, warum line 17 nicht funktioniert, aber line 18? Kann ich eine System.Address nicht direkt in eine Integer konvertieren (siehe line 17)?Konvertieren von System.Address zu Integer in Ada

main.adb

with Ada.Text_IO; 
with Ada.Unchecked_Conversion; 
with System.Storage_Elements; 

procedure Main is 
    package SSE renames System.Storage_Elements; 

    type Integer_Access is access Integer; 
    I1_Access : Integer_Access := new Integer'(42); 
    I1_Address : System.Address := I1_Access.all'Address; 

    function Convert1 is new Ada.Unchecked_Conversion (System.Address, Integer); 
    function Convert2 is new Ada.Unchecked_Conversion (System.Address, Integer_Access); 
begin 
    Ada.Text_IO.Put_Line (SSE.To_Integer (I1_Access'Address)'Img); 
    Ada.Text_IO.Put_Line (SSE.To_Integer (I1_Access.all'Address)'Img); 
    Ada.Text_IO.Put_Line (I1_Access.all'Img); 
    Ada.Text_IO.Put_Line (Convert1 (I1_Address)'Img); -- why does this NOT work? 
    Ada.Text_IO.Put_Line (Convert2 (I1_Address).all'Img); -- why does this work? 
end Main; 

Ergebnis

140734773254664 
140243203260416 
42 
-363855872 
42 

Antwort

6

Wenn ich Ihren Code auf diesem Mac mit -gnatwa (die meisten Warnungen) und -gnatl kompilieren (erzeugen eine Auflistung) I (excerpted) erhalten

12. function Convert1 is new Ada.Unchecked_Conversion (System.Address, Integer); 
     | 
    >>> warning: types for unchecked conversion have different sizes 

weil Integer 32 Bits, während System.Address (und die meisten Zugriffs Typen) sind 64-Bit. Ihre Maschine ist offensichtlich ähnlich.

Also der Grund, warum Sie eine seltsame 5. Ausgabe Linie bekommen (ich bekam -490720512, nebenbei bemerkt) ist, dass es nur auf die unteren 32 Bits der tatsächlichen Adresse.

Sie können System.Address_To_Access_Conversions (ARM 13.7.2) für die unterstützte Möglichkeit sehen, dies zu tun.

+0

Danke! Ich habe versucht 'Paket Convert3 ist neu System.Address_To_Access_Conversions (Integer);' mit 'Ada.Text_IO.Put_Line (Convert3.To_Pointer (I1_Address) .all'Img);' was funktioniert. Nun macht es auch Sinn, warum 'Convert1' nicht funktionieren kann. – user1091344

3

Es funktioniert. Anscheinend macht es etwas anderes als das, was Sie erwartet haben.

Sie können eine System.Address in eine Integer mit Unchecked_Conversion konvertieren, aber das Ergebnis wird nicht unbedingt sinnvoll sein. Sie erhalten eine Ganzzahl, die die (wahrscheinlich virtuelle) Adresse darstellt, die im Wert System.Address - nicht der Wert des Objekts, auf das es verweist, enthält. Und wenn System.Address und Integer nicht die gleiche Größe haben, wird das Ergebnis noch weniger sinnvoll sein.

Ada.Text_IO.Put_Line (Convert1 (I1_Address)'Img); 

Dieser druckt eine Integer Darstellung einer Speicheradresse. Es ist nicht besonders sinnvoll. (In der Regel würden Sie eine solche Adresse in hexadezimal sehen.)

Ada.Text_IO.Put_Line (Convert2 (I1_Address).all'Img); 

Dieser druckt die Integer Wert, 42 des Objekts an der Speicherstelle durch den Wert von I1_Address angezeigt. Es ist nur ein Umweg der Druck I1_Access.all.

+0

Danke! Also ist der korrekte Weg, um den Wert hinter einer 'System.Address' zu erhalten, die' System.Address' in den 'Integer' Zugriffstyp zu konvertieren und dann deneferenziert - wie ich es in Zeile 18 mache? – user1091344

+0

@ user1091344: In diesem Fall haben Sie bereits einen 'Integer_Access' Wert, den Sie in' System.Address' konvertieren und wieder zurück. Wenn Sie jedoch einen 'System.Address'-Wert von einer externen Quelle haben und auf das' Integer'-Objekt zugreifen müssen, auf das es zeigt, dann müssen Sie eine 'Unchecked_Conversion' durchführen, um sie in einen 'Access Integer'-Typ zu konvertieren dass du dereferenzieren kannst. (Wenn der Wert "System.Address" nicht gültig ist, kann dies in Ihrem Gesicht explodieren.) Aber tun Sie das nicht, es sei denn, Sie müssen es tatsächlich tun. (Es könnte eine sauberere Herangehensweise geben; ich war längere Zeit von Ada entfernt.) –

+1

@KeithThompson Die Verwendung von 'Unchecked_Conversion' zur Konvertierung zwischen' System.Address' und Zugriffsarten ist nicht zuverlässig. Bei Nicht-GNAT-Compilern könnte ein Zugriffstyp in einigen Fällen ein "fetter" Zeiger sein, der neben einer Adresse zusätzliche Daten enthält (z. B. Matrixgrenzen, Zugriffsebene, Stapelrahmenzeiger). 'System.Address_To_Access_Conversions' ist zuverlässiger. – ajb

3

Wenn Sie nur den Wert eines Bildes drucken möchten, wie in Ihrem Beispiel, verwenden Sie die Funktion System.Address_Image. Dies ist nicht gut für Zeigerarithmetik, führt aber zu einer besseren Ausgabe (zB hexadezimal)

Verwandte Themen