2016-05-31 3 views
1

В приведенном ниже примере мне интересно, почему line 17 не работает, но line 18? Могу ли я не преобразовать System.Address непосредственно в Integer (см. line 17)?Конвертировать из System.Address в Integer в 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; 

Результат

140734773254664 
140243203260416 
42 
-363855872 
42 

ответ

6

Если я скомпилировать код на этом компьютере с -gnatwa (большинство предупреждений) и -gnatl (сгенерировать список) Я получаю (Выдержки)

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

Integer потому, что составляет 32 бита, а System.Address (и большинство доступа типы) - 64 бит. Ваша машина, очевидно, похожа.

Итак, причина, по которой вы получаете странную 5-ю выходную линию (кстати, я получил -490720512), заключается в том, что она смотрит только на нижние 32 бита фактического адреса.

Вы можете посмотреть на System.Address_To_Access_Conversions (ARM 13.7.2) для поддерживаемого способа для этого.

+0

Спасибо! Я попробовал 'пакет Convert3 - это новый System.Address_To_Access_Conversions (Integer);' с 'Ada.Text_IO.Put_Line (Convert3.To_Pointer (I1_Address) .all'Img);' который работал. Теперь имеет смысл, почему 'Convert1' не может работать. – user1091344

3

Это делает работу. Видимо, это делает что-то другое, чем вы ожидали.

Вы можете конвертировать System.Address в Integer с использованием Unchecked_Conversion, но результат не обязательно будет значимым. Вы получите целое число, представляющее (возможно, виртуальный) адрес, хранящийся в значении System.Address, - , а не значение любого объекта, на который он указывает. И если System.Address и Integer не имеют одинакового размера, результат будет еще менее значимым.

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

Это печатает Integer представление адреса памяти. Это не имеет особого значения. (Как правило, вы хотели бы видеть такой адрес в шестнадцатеричном формате.)

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

Это печатает значение Integer, 42, объект в ячейке памяти, указанной величиной I1_Address. Это всего лишь окольный способ печати I1_Access.all.

+0

Спасибо! Итак, правильный способ получить значение за «System.Address» - это преобразовать «System.Address» в тип доступа «Integer», а затем разыменовать его - как я это делаю в строке 18? – user1091344

+0

@ user1091344: В этом случае у вас уже есть значение Integer_Access, которое вы конвертируете в 'System.Address' и обратно. Но если у вас есть значение 'System.Address' от какого-то внешнего источника, и вам нужно получить доступ к объекту Integer, на который он указывает, то да, вам нужно сделать' Unchecked_Conversion', чтобы преобразовать его в некоторый тип 'Access Integer' что вы можете разыменовать. (Если значение 'System.Address' недействительно, это может взорваться в вашем лице.) Но не делайте этого, если вам действительно не нужно. (Может быть, более чистый подход, я давно не был в Аде.) –

+1

@KeithThompson Использование 'Unchecked_Conversion' для преобразования между' System.Address' и типами доступа не является надежным. В компиляторах, отличных от GNAT, тип доступа в некоторых случаях может быть «жирным» указателем, который содержит дополнительные данные, кроме адреса (например, границы массива, уровень доступности, указатель фрейма стека). 'System.Address_To_Access_Conversions' является более надежным. – ajb

3

Если вы хотите только напечатать значение изображения, как в вашем примере, рассмотрите возможность использования функции System.Address_Image. Это не хорошо для арифметики указателя, но приводит к лучшему выводу (например, шестнадцатеричный)