tags:

views:

119

answers:

3
+1  Q: 

Ada array access

Hello, I'm working in Ada95, and I'm having difficulty figuring out pointers.

I have code that looks like the following:

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;

This fails compilation on the definition of pointer, saying

"The prefix to 'ACCESS must be either an aliased view of an object or denote a subprogram with a non-intrinsic calling convention"

If I then change the definition of the vector itself to:

my_vec : aliased vector  

it now returns the compiler error:

"The expected type for X'ACCESS, where X denotes and aliased view of an object, must be a general acces type"

At the end of the day what I really need is a pointer to a specific item within the array, the position being dynamic based on input parameters. Can anyone point me in the right direction?

+1  A: 

Think I found it, for anyone else running into the same issue.

The answer has to do with what specifically is being aliased. The array declaration needs to be:

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

in order to make sure the integers are stored in memory, and not registers.

Bryan
I don't know what compiler you're using, but it's not likely GNAT GPL 2010, because that change to your vector declaration generates exactly the same error. And the use of "aliased" has nothing to do with specifying whether the compiler maintains variables in memory or registers, it simply is used to mark variables that may be the target of an access value--which *may* affect how the compiler allocates their storage, but implies nothing beyond that.
Marc C
In fact, I'm using an older version of GreenHills AdaMulti (...not by choice). Thanks for the clarification on the aliased keyword; I was just going off of what I'd found on other sites.
Bryan
BTW Bryan, if you feel this is truly the answer to your question, you should also "accept" it. The main reason is that will tell both the SO system and other users that an answer was found. A secondary reason is that your accept rate (the % of questions you ask and eventually accept an answer from) is public. Some people here on SO don't like to answer questions from people with low accept rates. I know it seems a bit cheesy to be accepting your own answer, but its better than the alternative.
T.E.D.
+1  A: 

If you're using GNAT, the error message after the "must be a general access type" should have given you the solution:

add "all" to type "vector_access" defined at line ...

so that you would end up with:

type Vector_Access is access all Vector;

The use of "all" to designate a general access type has to do with dynamic memory allocation pools in Ada. If you don't care about dynamic memory allocation pools, then don't worry about it, and just include "all" in your access type definitions.

I'm not sure if this is part of what you're looking for at the end of the day, but you are aware that in most circumstances Ada's access (pointer) types are used to handle dynamically allocated memory, right?

So instead of pointing my_vec at an aliased variable, you would dynamically allocate it:

Pointer_2_Dynamic : vector_access := new Vector;

This way you can dynamically allocate at runtime the objects you need, and easily handle variably sized ones (though you'd need a different vector definition to accomplish that:

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);
Marc C
Thanks for the tip Marc. The all keyword was definitely a part of what I was looking for. Unfortunately, I'm actually restricted from allocating any dynamic memory by the overall requirements, and in this case what I'm doing is returning the global value that may or may not need to be modified, so I think using pointers is appropriate in my case, but your point is well taken. Appreciate the input!
Bryan
+2  A: 

OK. Lesson one on Ada for expert Cish coders: Ada parameters are different than Cish parameters. In C, (pre-reference parameters) every single parameter is the equivalent of an Ada 'in' parameter, with an extra proviso that the C compiler must always stupidly pass the entire thing on the stack, no matter how huge it is. So you poor C coders get it nailed into your brains that you never pass large objects into subroutines directly, but always use pointers.

Ada is different. You tell the compiler how you want to access your parameters (read only - 'in', write only - 'out', or read write - 'in out'). However, that has nothing to do with how parameters are passed. The parameter passing mechanisim is up to the compiler, and the compiler will chose the most efficient way to do it. In practice, on nearly all platforms, that means than anything too big for a register will be passed by reference. But this is an implementation detail, and is the compiler's business, not yours. You shouldn't even have to think about it, except in really rare cases.

So grit your teeth and pass that array naked as an in parameter. Trust me, you'll get to like it.

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

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

Ada is designed to be quite usable in nearly all cases without needing pointers, and usable in all but a very few very rare cases without needing pointers to stack-allocated objects.

The former is fairly unsafe (dangers from unallocated pointers and memory leaks), and the latter is even more unsafe (stack objects may go out of scope before your pointer does, and even if they don't one little size error can corrupt your entire program). You can still do both in Ada, but unlike many languages it is designed to make unsafe things require a bit more work on your part to do, and make very unsafe things a major PITA to write.

For example, if you'd just dynamically allocate the entire array, you wouldn't have to fool with this aliased and all business. Furthermore, if you just want to pass the array into a subroutine, you could simply pass it as a parameter and you don't even have to fool with the dynamic allocations and deallocations. Again, Ada compilers are smart enough to pass large objects by reference (yes, even if you specified in). This takes an attitude adjustment from C/C++ coders, who are used to having to tell their dumbass compiler not to pass 10meg objects on the stack. You have to learn to let the Ada compiler worry about how to pass your parameters around efficiently, and you can just worry about how to write great code.

T.E.D.
Thanks TED. That sounds awesome in theory, but how can you be positive it *is* passing it by reference? The last thing I need is some bug popping up where I think I've modified my global, but really all I've done is change a value on the stack that no one outside of my current frame can see. I'll certainly need a better understanding of the limitations before I can write something without testing it in-depth each and every time...
Bryan
Hah. Figured that was it. Ada noobs who are C experts always have a really tough time with this one (strings is the other one you will probably have trouble groking). Yes, you **can** be sure of it. If you ever discover an Ada compiler that isn't passing objects larger than a register can hold by reference, report it as a bug, because it is one. Just make your parameter `in out`, and go on your merry way.
T.E.D.
@Bryan - OK. Rewrote my answer a bit based on your comment. Pls reread (at leat the top half) and tell me if it is more helpful
T.E.D.
Appreciate you're taking the time to clarify things for me here TED, very helpful. I'm still going to be scared something I'm passing will fit in a register, but I guess anytime you declare it "in out" you really are telling the compiler you want to be adjusting the "real" thing, not a copy of it. Scary! You're probably right though, it seems like that can help avoid a lot of headaches.
Bryan
Right. If it makes you feel better, think of Ada parameters as like C++ reference parameters, except that the compiler can revert to passing by copy for small `in` parameters if it feels like it.
T.E.D.