Доступ к массиву Ada: указатель на определенный элемент в массиве, положение которого изменяется в зависимости от входных параметров.

Я работаю в Ada95, и мне трудно разобраться с указателями.

У меня есть код, который выглядит следующим образом:

type vector is array (1 .. 3) of integer;   
type vector_access is access vector;

my_vec : vector;

procedure test is  
  pointer : vector_access := my_vec'access;  
begin   
  ...  
end;

Это не дает компиляции определения указателя, говоря

«Префикс к «ДОСТУП» должен быть либо псевдонимом объекта, либо обозначать подпрограмму с невнутренним соглашением о вызовах»

Если я затем изменю определение самого вектора на:

my_vec : aliased vector  

теперь он возвращает ошибку компилятора:

«Ожидаемый тип для X'ACCESS, где X обозначает вид объекта с псевдонимом, должен быть общим типом доступа»

В конце концов, что мне действительно нужно, так это указатель на конкретный элемент в массиве, позиция которого является динамической на основе входных параметров. Может кто-то указать мне верное направление?


person Bryan    schedule 23.09.2010    source источник


Ответы (3)


Если вы используете GNAT, сообщение об ошибке после «должен быть тип общего доступа» должно было дать вам решение:

добавьте «все» к типу «vector_access», определенному в строке ...

чтобы у вас получилось:

type Vector_Access is access all Vector;

Использование «всех» для обозначения общего типа доступа связано с пулами динамического выделения памяти в Аде. Если вы не заботитесь о пулах динамического выделения памяти, не беспокойтесь об этом и просто включите «все» в определения вашего типа доступа.

Я не уверен, является ли это частью того, что вы ищете в конце дня, но вы знаете, что в большинстве случаев типы доступа (указатели) Ады используются для обработки динамически выделяемой памяти, верно?

Таким образом, вместо того, чтобы указывать my_vec на переменную с псевдонимом, вы должны динамически выделить ее:

Pointer_2_Dynamic : vector_access := new Vector;

Таким образом, вы можете динамически выделять во время выполнения нужные вам объекты и легко обрабатывать объекты переменного размера (хотя для этого вам потребуется другое определение вектора:

type Dynamic_Vector is array (Natural range <>) of Integer;
type Dynamic_Vector_Access is access Dynamic_Vector;

N : Natural := 10; -- Variable here, but could be a subprogram parameter.
Dyn_Vector : Dynamic_Vector_Access := new Dynamic_Vector(1..N);
person Marc C    schedule 23.09.2010
comment
Спасибо за совет Марк. Ключевое слово all определенно было частью того, что я искал. К сожалению, я фактически ограничен в выделении какой-либо динамической памяти общими требованиями, и в этом случае я возвращаю глобальное значение, которое может потребоваться или не измениться, поэтому я думаю, что использование указателей уместно в моем случае. случай, но ваша точка зрения хорошо принята. Цените вклад! - person Bryan; 24.09.2010

ХОРОШО. Первый урок по Ada для опытных программистов Cish: параметры Ada отличаются от параметров Cish. В C (параметры предварительной ссылки) каждый отдельный параметр является эквивалентом параметра Ada 'in', с дополнительной оговоркой, что компилятор C всегда должен тупо передавать все это в стеке, независимо от того, насколько он огромен. Итак, вы, бедные программисты на C, вбили себе в голову, что вы никогда не передаете большие объекты в подпрограммы напрямую, а всегда используете указатели.

Ада другая. Вы сообщаете компилятору, как вы хотите получить доступ к своим параметрам (только чтение — «вход», только запись — «выход» или чтение и запись — «вход-выход»). Однако это не имеет ничего общего с тем, как передаются параметры. Механизм передачи параметров зависит от компилятора, и компилятор выберет наиболее эффективный способ сделать это. На практике почти на всех платформах это означает, что все, что слишком велико для регистра, будет передаваться по ссылке. Но это деталь реализации, и это дело компилятора, а не ваше. Вы даже не должны думать об этом, за исключением очень редких случаев.

Так что стисните зубы и передайте этот массив в чистом виде как параметр in out. Поверьте, вам понравится.

type vector is array (natural range <>) of integer;
my_vec : vector(1..3); 

procedure test (subject : in out vector) is   
begin    
  ...   
end; 

Ада спроектирована таким образом, чтобы ее можно было использовать почти во всех случаях без указателей, и ее можно было использовать во всех случаях, кроме очень немногих очень редких, без необходимости указателей на объекты, размещенные в стеке.

Первый довольно небезопасен (опасность из-за нераспределенных указателей и утечек памяти), а второй еще более небезопасен (объекты стека могут выйти за пределы области видимости раньше, чем ваш указатель, и даже если они этого не сделают, одна маленькая ошибка размера может повредить всю вашу память). программа). Вы по-прежнему можете делать и то, и другое на Аде, но, в отличие от многих языков, он предназначен для того, чтобы небезопасные вещи требовали немного больше работы с вашей стороны, а очень небезопасные вещи требовали написания основного PITA.

Например, если бы вы просто динамически выделяли весь массив, вам не пришлось бы возиться с этими aliased и all делами. Кроме того, если вы просто хотите передать массив в подпрограмму, вы можете просто передать его в качестве параметра, и вам даже не придется возиться с динамическим выделением и освобождением. Опять же, компиляторы Ады достаточно умны, чтобы передавать большие объекты по ссылке (да, даже если вы указали in). Это требует корректировки отношения кодеров C/C++, которые привыкли говорить своему тупому компилятору, чтобы он не пропускал 10-мегабайтные объекты в стек. Вы должны научиться позволять компилятору Ada заботиться о том, как эффективно передать ваши параметры, и вы можете просто беспокоиться о том, как написать отличный код.

person T.E.D.    schedule 23.09.2010
comment
Спасибо ТЭД. В теории это звучит потрясающе, но как вы можете быть уверены, что он передает его по ссылке? Последнее, что мне нужно, это всплывающая ошибка, когда я думаю, что изменил свой глобальный, но на самом деле все, что я сделал, это изменил значение в стеке, которое никто за пределами моего текущего фрейма не может видеть. Мне, безусловно, нужно лучше понять ограничения, прежде чем я смогу что-то написать без тщательного тестирования каждый раз... - person Bryan; 27.09.2010
comment
Ха. Прикинул, что это было. Новичкам Ады, которые являются экспертами в C, всегда очень тяжело с этим (строки — это еще один, с которым у вас, вероятно, возникнут проблемы). Да, вы можете быть в этом уверены. Если вы когда-нибудь обнаружите компилятор Ады, который не передает объекты большего размера, чем регистр может храниться по ссылке, сообщите об этом как об ошибке, потому что это так. Просто сделайте свой параметр in out и идите своей веселой дорогой. - person T.E.D.; 28.09.2010
comment
@ Брайан - хорошо. Немного переписал мой ответ на основе вашего комментария. Пожалуйста, перечитайте (хотя бы верхнюю половину) и скажите, будет ли это более полезным. - person T.E.D.; 28.09.2010
comment
Благодарю вас за то, что вы нашли время, чтобы разъяснить мне некоторые вещи здесь, TED, очень полезно. Я все еще буду бояться, что что-то, что я передаю, поместится в регистр, но я думаю, что каждый раз, когда вы объявляете это вне, вы действительно говорите компилятору, что хотите настроить реальную вещь, а не ее копию. Страшный! Вы, наверное, правы, кажется, что это может помочь избежать многих головных болей. - person Bryan; 28.09.2010
comment
Верно. Если вам от этого станет легче, думайте о параметрах Ады как о ссылочных параметрах C++, за исключением того, что компилятор может вернуться к передаче путем копирования для небольших in параметров, если он захочет. - person T.E.D.; 28.09.2010

Думаю, я нашел это, для всех, кто сталкивается с той же проблемой.

Ответ связан с тем, что конкретно используется в качестве псевдонима. Объявление массива должно быть:

type vector is array (1 .. 3) of aliased integer;

чтобы убедиться, что целые числа хранятся в памяти, а не в регистрах.

person Bryan    schedule 23.09.2010
comment
Я не знаю, какой компилятор вы используете, но вряд ли это GNAT GPL 2010, потому что это изменение в объявлении вашего вектора вызывает точно такую ​​же ошибку. И использование aliased не имеет ничего общего с указанием того, поддерживает ли компилятор переменные в памяти или регистрах, оно просто используется для пометки переменных, которые могут быть целью значения доступа, что может повлиять на то, как компилятор выделяет их память, но ничего кроме этого не подразумевает. - person Marc C; 23.09.2010
comment
На самом деле я использую более старую версию GreenHills AdaMulti (... не по своему выбору). Спасибо за разъяснение ключевого слова с псевдонимом; Я просто исходил из того, что нашел на других сайтах. - person Bryan; 24.09.2010