What is the correct syntax for initializing a dynamically allocated array in Ada? I have tried this:
type Short_Array is array (Natural range <>) of Short;
Items : access Short_Array;
Items := new Short_Array(1..UpperBound)'(others => 0);
which results in a compiler error - "binary operator expected". And this:
type Short_Array is array (Natural range <>) of Short;
Items : access Short_Array;
Items := new Short_Array(1..UpperBound);
Items.all := (others => 0);
which seems to raise a SEGFAULT surprisingly. Not sure what's going on there but wanted to get the syntax right before I start chasing my tail.
If you are using Ada2012 you can do the following:
type Short_Array is array(Natural range <>) of Short with
Default_Component_Value => 0;
Items : access Short_Array := new Short_Array(1..UpperBound);
The use of default initial values for arrays is explained in section 2.6 of the Ada 2012 Rationale http://www.ada-auth.org/standards/12rat/html/Rat12-2-6.html
Another approach in Ada is to define the record as a discriminant record, with the discriminant determining the size of the array field.
type Items_Record (Size : Natural) is record
-- Some non-array fields of your record
Items : Short_Array(1..Size);
end record;
An instance of the record can then be allocated in an inner block
Get(Items_Size);
declare
My_Record : Items_Record(Size => Items_Size);
begin
-- Process the instance of Items_Record
end;
The record is dynamically allocated on the stack. If the record size is very large you will encounter a stack overflow issue. If not, this works very well. One advantage of this approach is the instance is automatically de-allocated when the end of the block is reached.
The SEGFAULT in your second example comes most certainly from the initialization.
Compare
type Short_Array is array (Natural range <>) of Short;
Items : access Short_Array;
Items := new Short_Array(1..UpperBound);
Items.all := (others => 0);
And this:
type Short_Array is array (Natural range <>) of Short;
Items : access Short_Array;
Items := new Short_Array(1..UpperBound);
for I in 1..UpperBound loop
Items(I) := 0;
end loop;
And play with different values of ulimit -Ss which sets the allowed size of the stack.
The point is that
Items.all := (others => 0);
allocates an array on the stack and copy it in your heap-allocated array. So you think you are working on the heap but still needs a lot of stack. If your array is too big for your ulimit -Ss (or considering both soft and hard limits ulimit -s), you will segfault (or get a STORAGE_ERROR) though you think you are all on the heap.
To mitigate this problem, (though it might not work in every situation, eg if UpperBound is dynamic…), you can compile your code either with:
"-fstack-usage" (to get usage information for each unit)
"-Wstack-usage=2000" (or any limit more accurate to your case, see gnat's documentation for more infos) to yield warnings for functions using too much stack (or having unbounded stack usage).
The second option could have issued a warning and pointed you to your stack overflow.
Related
My question is: what are the benefits of using pointers and reference to?
I am new to codesys and in my previous job, I programmed in TIA portal (Siemens) and Sysmac Studio (Omron) and never came across pointers or something similar. I think I understand how they work but not sure when I should be using them myself.
For example, I just received a function block from a supplier:
Why don't they just have an array for input and output?
First of all, if you have ever used the VAR_IN_OUT declaration, then you have already used references, since that is equivalent to a VAR with REFERENCE TO.
As for the uses, there are mainly 4 that I can think of right now:
Type Punning, which you can also achieve using a UNION, but you may not want to have to create a union for every single reinterpretation cast in your code.
TL; DR: To save memory and copy execution time. Whenever you pass some data to a function/function block, it gets copied. This is not a big problem if your PLC has enough CPU power and memory, however if you are dealing with especially huge data on a low end PLC, then you may either exceed real time execution constraints, or run out of memory. When you pass a pointer/reference however, no matter how big the data is only the pointer/reference gets copied and passed, which is 4 bytes in 32 bit system, and 8 bytes in a 64 bit one.
In C style languages you'd use pointers/references when you want a function to return multiple values without the hassle of creating a custom structure every time. You can do the same here to, however in CODESYS function can have multiple outputs, for example:
VAR_OUPUT
out1 : INT; (*1st output variable *)
out2 : INT; (*2nd output variable *)
//...
END_VAR
And finally, as I mentioned at the very beginning, when you want to pass some data that needs to be modified in the function itself, in other words, where you can use VAR_IN_OUT you can also use pointers/references. One Special case where you will have to use a pointer is if you have a Function Block that receives some data in the FB_Init (initialization/construction) function and stores it locally. In such case you would have a pointer as a local variable in the function block, and take the address of the variable in the FB_Init function. Same applies if you have a structure that needs to reference another structure or some data.
PS. There are probably some other uses I missed. One of the main uses in other languages is for dynamic memory allocations, but in CODESYS this is disabled by default and not all PLCs support it, and hardly anyone (that I know) uses it.
EDIT: Though this has been accepted, I want to bring a real life example of us using pointers:
Suppose we want to have a Function Block that calculates the moving average on a given number series. A simple approach would be something like this:
FUNCTION_BLOCK MyMovingAvg
VAR_INPUT
nextNum: INT;
END_VAR
VAR_OUTPUT
avg: REAL;
END_VAR
VAR
window: ARRAY [0..50] OF INT;
currentIndex: UINT;
END_VAR
However, this has the problem that the moving window size is static and predefined. If we wanted to have averages for different window sizes we would either have to create several function blocks for different window sizes, or do something like this:
FUNCTION_BLOCK MyMovingAvg
VAR CONSTANT
maxWindowSize: UINT := 100;
END_VAR
VAR_INPUT
nextNum: INT;
windowSize: UINT (0..maxWindowSize);
END_VAR
VAR_OUTPUT
avg: REAL;
END_VAR
VAR
window: ARRAY [0..maxWindowSize] OF INT;
currentIndex: UINT;
END_VAR
where we would only use the elements of the array from 0 to windowSize and the rest would be ignored. This however also has the problems that we can't use window sizes more than maxWindowSize and there's potentially a lot of wasted memory if maxWindowSize is set high.
There are 2 ways to get a truly general solution:
Use dynamic allocations. However, as I mentioned previously, this isn't supported by all PLCs, is disabled by default, has drawbacks (you'll have to split you memory into two chunks), is hardly used and is not very CODESYS-like.
Let the user define the array of whatever size they want and pass the array to our function block:
FUNCTION_BLOCK MyMovingAvg
VAR_INPUT
nextNum: INT;
END_VAR
VAR_OUTPUT
avg: REAL;
END_VAR
VAR
windowPtr: POINTER TO INT;
windowSize: DINT;
currentIndex: UINT;
END_VAR
METHOD FB_Init: BOOL
VAR_INPUT
bInitRetains: BOOL;
bInCopyCode: BOOL;
END_VAR
VAR_IN_OUT // basically REFERENCE TO
window_buffer: ARRAY [*] OF INT; // array of any size
END_VAR
THIS^.windowPtr := ADR(window_buffer);
THIS^.windowSize := UPPER_BOUND(window_buffer, 1) - LOWER_BOUND(window_buffer, 1) + 1;
// usage:
PROGRAM Main
VAR
avgWindow: ARRAY [0..123] OF INT; // whatever size you want!
movAvg: MyMovingAvg(window_buffer := avgWindow);
END_VAR
movAvg(nextNum := 5);
movAvg.avg;
The same principle can be applied to any function block that operates on arrays (for example, we also use it for sorting). Moreover, similarly you may want to have a function that works on any integer/floating number. For that you may use one of the ANY types which is basically a structure that holds a pointer to the first byte of the data, the size of the data (in bytes) and a type enum.
Assume having the following setup:
type My is new Integer;
type My_Acc is access My;
procedure Replace(Self : in out My_Acc; New_Int : Integer)
with Pre => New_Int /= Self.all, Post => Self'Old.all /= Self.all;
Note: Code above might not be fully valid, but I hope the concept is understandable.
Now what happens if Unchecked_Deallocation() is used on Self inside Replace
and a new Integer is allocated and set to Self (This should result in Self'Old pointing to a now invalid memory location)?
Does Ada keep kind of a snapshot where Self'Old points to the previous memory location, but before Unchecked_Deallocation() is executed?
If Self'Old would get invalid for use in the Post contract, how could you still access the previous value? Is it possible to create a manual snapshot in the Pre contract that can then be used in Post? Maybe it can be achieved using Ghost_Code?
I want to make everything in Spark, in case that changes something.
Edit: Fixed Self to in out as mentioned by Simon Wright.
Edit: Fixed type of Self to allow null
It may be that the latest versions of SPARK support access types; it used not to, at all.
First, your Not_Null_My_Acc needs to be a subtype of My_Acc, unless you meant it to be a type in its own right.
Second, you can’t deallocate Self inside Replace and allocate a new value; Self is in-mode, & hence not writable.
Third, you can’t apply ’Old to Self, because
warning: attribute "Old" applied to constant has no effect
What you can say is
Post => Self.all'Old /= Self.all;
In ARM 6.1.1(26ff) it says
Each X'Old in a postcondition expression that is enabled denotes a constant that is implicitly declared at the beginning of the subprogram body, entry body, or accept statement.
The implicitly declared entity denoted by each occurrence of X'Old is declared as follows:
...
X'Old : constant S := X;
... in other words, nothing fancy is expected, just a straight copy of (in this case) Self: not Self.all.
So, if your Replace deallocates Self, then Self’Old is a dangling reference, and erroneous.
I suggested previously that changing the postcondition to
Post => Self.all'Old /= Self.all;
would be safe; why wouldn’t that meet your requirements? is there something going on you haven’t told us about?
Note the subtle difference between Self’Old.all and Self.all’Old. The first one takes a copy of Self as it was before the call, which gets dereferenced after the call (by which time it’s pointing into hyperspace), while the second one dereferences the prior Self and copies the integer value it finds there; on return that’s still valid.
I'm playing around with ADA, trying to get my grips on it. I still have a hard time figuring out the discriminant part though. I have a task with one discriminant, and I'm trying to pass a duration to it. However it tells me:
package Procedures is
task type WhatchDog(dur : Duration := 1.0) is
entry Reset(start : in Time);
entry Sync(timedOut : out Boolean);
end WhatchDog;
end Procedures;
with Procedures;
procedure Main is
watch : Procedures.WhatchDog(dur => 0.5);
begin
null;
end Main;
Discriminants must have a discrete or access type.
When I change my discriminant type to an access type,
task type WhatchDog(dur : access Duration := 1.0) is
it gives me the following warning:
Expected an access type with designated type "Standard Duration"
Found type universal real
I know there are other ways to realize a constructor, such as creating an entry point. But I would like to know what I'm doing wrong here, and understand the error I'm making.
The google work I've done so far doesn't really shine any light on this, and only makes use of real types which seem to work fine. Here for example:
http://www.adaic.org/resources/add_content/docs/95style/html/sec_6/6-1-3.html
In your attempted workaround you're trying to assign a Duration to an Access. The proper assignment would be, if going that way:
task type WatchDog (Dur : access Duration := new Duration'(1.0)) is
at the price of having an allocation that is never deallocated, that is, a minor memory leak. That could be a problem if you create/destroy many instances of the task type during a long-lived program, but in that case you have to also take care of reaping the tasks (at least in Gnat).
In this case, I would either have a first entry to pass the Duration value to the task, or a value in milliseconds (or whatever is appropriate) using a Natural as discriminant, and converting it inside the task. Certainly it is an itch in the language.
I am not sure this is the intended use of discriminants. Here, duration is really a configuration of your instances, but doesn't impact the layout of the type in memory. So I think it would be better (and certainly more usual) to either have a Configure entry that can be called to do the initial setup, or if this really needs to be given when the instance is created, you could try creating a generic with a formal Duration parameter.
The reason that you cannot assign 1.0 to dur (the access discriminant) is that dur is of a pointer type (anonymous, access to Duration) while 1.0 is a numeric literal. In short, you cannot assign a real value to a pointer variable, only a pointer value to a pointer variable. See Alex's answer for one way to get one.
The type Duration is not a discrete type, i.e. neither integral nor enumerated. But discrete is what a discriminant must be if not of an access type, given discriminants' original intent as outlined by manuBriot.
So, to initialize some aspect of task objects by passing a value for dur, you need pointers. The following small rewrite does not use an allocator (new), it uses names for duration values, of which it then takes the pointer using 'Access.
package Procedures is
Duration_By_Default : aliased constant Duration := 1.0;
task type Whatchdog
(dur : access constant Duration := Duration_By_Default'Access)
is
entry Reset(start : in Time);
entry Sync(timedOut : out Boolean);
end WhatchDog;
end Procedures;
with Procedures;
procedure Main is
Desired_Duration : aliased constant Duration := 0.5;
watch : Procedures.WhatchDog(dur => Desired_Duration'Access);
begin
null;
end Main;
Note the implications of having an access value point to a variable duration, instead of a constant duration as shown here.
Alternatively, perform a computation that produces a Duration value from some integer discriminant, named dur_in_msec, say.
task body Whatchdog is
dur : constant Duration := Duration(Float(dur_in_msec) / 1_000.0);
I am trying to apply OpenMP to a large Fortran code.
Presumably to reuse memory many loops rely on work arrays that are created during initialisation. The loops access them through a long series of pointers.
Now according to the standard any PRIVATE() variables in Fortran must be either allocatable or defineable. Is their is way to dereference this pointer mess or is my best option to create a new variable with allocate(foo, source=bar)?
The complete structure I am dealing with is something like this:
type work_type
allocatable :: bar
end type
type(work_type) :: work
pointer, type(work_type) :: w
w => work
pointer :: foo, bar
bar => w%bar
foo => bar
Or to summarise:
for => bar => w%bar
w => work
If I get your question correctly, your problem is with the initialization of private pointers to the same memory location when inside a parallel region.
If this is the case, then you should use the copyprivate clause of the single worksharing directive. This clause permits to broadcast the value of a private variable to other threads:
REAL, POINTER :: A(:)
...
!$OMP SINGLE
ALLOCATE(A,10)
!$OMP SINGLE COPYPRIVATE(A)
! SPACE IS ALLOCATED ONLY ONCE BUT EVERY THREAD HAS A PRIVATE POINTER TO IT
The relevant quotes from the OpenMP 4.0. Standard should be:
The copyprivate clause provides a mechanism to use a private
variable to broadcast a value from the data environment of one
implicit task to the data environments of the other implicit tasks
belonging to the parallel region.
...
If the list item has the POINTER attribute, then, in all other
implicit tasks belonging to the parallel region, the list item
receives, as if by pointer assignment, the same association status of
the corresponding list item in the implicit task associated with the
thread that executed the structured block.
The full description of the clause (in case you are interested) is in section 2.14.1.2.
I am making a program in Ada for Data Structures and Algorithms class.
My current problem is the error 'actual for "this" must be a variable'
I did some looking around and I read about it being because of in out mode, but I'm not entirely grasping why it's happening to me I guess.
The Examples I seen made sense but I guess since it's my coding I'm just not seeing it?
Procedure AddUnmarked(g:Grid; this:Linked_List_Coord.List_Type; c:Cell) is
cNorth : Cell := getCell(g, North(c));
cEast : Cell := getCell(g, East(c));
cSouth : Cell := getCell(g, South(c));
cWest : Cell := getCell(g, West(c));
Begin
if CellExists(g, cNorth) and not cNorth.IsMarked then
Linked_List_Coord.Append(this, cNorth.Coords);
elsif CellExists(g, cEast) and not cEast.IsMarked then
Linked_List_Coord.Append(this, cEast.Coords);
elsif CellExists(g, cSouth) and not cSouth.IsMarked then
Linked_List_Coord.Append(this, cSouth.Coords);
elsif CellExists(g, cWest) and not cWest.IsMarked then
Linked_List_Coord.Append(this, cWest.Coords);
end if;
End AddUnmarked;
before "this" is passed to the function it is a Linked_List of my self defined type Coord (2 integers). It is initialized and has had a Coordinate pair added to it before the list is passed to the function above in my code.
What it means is that the list cannot be modified unless you are passing it as a modifiable parameter, that is, in out.
To elaborate, think of LIST_TYPE as being a handle to a tagged-type object; in order to ensure that LIST_TYPE is valid you need to pass it in via an in parameter (or create/manipulate a local object), but to pass out your results you need an out parameter.
So, in order to do your operations on an already-existing object {and get the results back} you need in out.
In Ada, subroutine parameters all have a usage mode associated with them. The available modes are in, out, and in out*. If you don't specify a mode, (like you didn't in your code), then it defaults to in only.
The modes specify what you can do with that parameter on the inside of the subprogram. If you want to read a value passed in from outside the routine, it must have in on it. If you want to write to the parameter (and/or possibly have it read outside the routine), then it must have out on it.
Since none of your parameters have out on them, you cannot write to any of them.
(* - There's another possible mode: access, but that's an advanced topic).