Translating C flexible array members with length fields to Ada - ada

While writing bindings for interfacing with C code, I am finding issues translating the numerous instances of structs with flexible array members to Ada, as such
struct example {
size_t length;
int body[];
};
I've been told for Ada that behaviors like that can be replicated with discriminated types, but I cannot find a way to use the length field as a discriminant, while maintaining the layout of the structure so that the records can be used to interface with the C code, something like
type Example (Count : Integer := Length) is record
Length : Unsigned_64;
Body : Integer (1 .. Count);
end record;
Is there any way to create a type like that with that array? I've been defaulting for now to grabbing the address of that location and declaring the array myself on place for use, is there any better way? Thanks in advance.

Here is an example in which Ada code calls C code, passing objects of this kind from Ada to C and from C to Ada. The C header is c_example.h:
typedef struct {
size_t length;
int body[];
} example_t;
extern void example_print (example_t *e /* in */);
// Print the contents of e.
extern example_t * example_get (void);
// Return a pointer to an example_t that remains owned
// by the C part (that is, the caller can use it, but should
// not attempt to deallocate it).
The C code is c_example.c:
#include <stdio.h>
#include "c_example.h"
void example_print (example_t *e /* in */)
{
printf ("C example: length = %zd\n", e->length);
for (int i = 0; i < e->length; i++)
{
printf ("body[ %d ] = %d\n", i, e->body[i]);
}
} // example_print
static example_t datum = {4,{6,7,8,9}};
example_t * example_get (void)
{
return &datum;
} // example_get
The C-to-Ada binding is defined in c_binding.ads:
with Interfaces.C;
package C_Binding
is
pragma Linker_Options ("c_example.o");
use Interfaces.C;
type Int_Array is array (size_t range <>) of int
with Convention => C;
type Example_t (Length : size_t) is record
Bod : Int_Array(1 .. Length);
end record
with Convention => C;
type Example_ptr is access all Example_t
with Convention => C;
procedure Print (e : in Example_t)
with Import, Convention => C, External_Name => "example_print";
function Get return Example_Ptr
with Import, Convention => C, External_Name => "example_get";
end C_Binding;
The test main program is flexarr.adb:
with Ada.Text_IO;
with C_Binding;
procedure FlexArr
is
for_c : constant C_Binding.Example_t :=
(Length => 5, Bod => (55, 66, 77, 88, 99));
from_c : C_Binding.Example_ptr;
begin
C_Binding.Print (for_c);
from_c := C_Binding.Get;
Ada.Text_IO.Put_Line (
"Ada example: length =" & from_c.Length'Image);
for I in 1 .. from_c.Length loop
Ada.Text_IO.Put_Line (
"body[" & I'Image & " ] =" & from_c.Bod(I)'Image);
end loop;
end FlexArr;
I build the program thusly:
gcc -c -Wall c_example.c
gnatmake -Wall flexarr.adb
And this is the output from ./flexarr:
C example: length = 5
body[ 0 ] = 55
body[ 1 ] = 66
body[ 2 ] = 77
body[ 3 ] = 88
body[ 4 ] = 99
Ada example: length = 4
body[ 1 ] = 6
body[ 2 ] = 7
body[ 3 ] = 8
body[ 4 ] = 9
So it seems to work. However, the Ada compiler (gnat) gives me some warnings from the C_Binding package:
c_binding.ads:14:12: warning: discriminated record has no direct equivalent in C
c_binding.ads:14:12: warning: use of convention for type "Example_t" is dubious
This means that while this interfacing method works with gnat, it might not work with other compilers, for example Ada compilers that allocate the Bod component array separately from the fixed-size part of the record (whether such a compiler would accept Convention => C for this record type is questionable).
To make the interface more portable, make the following changes. In C_Binding, change Length from a discriminant to an ordinary component and make Bod a fixed-size array, using some maximum size, here 1000 elements as an example:
type Int_Array is array (size_t range 1 .. 1_000) of int
with Convention => C;
type Example_t is record
Length : size_t;
Bod : Int_Array;
end record
with Convention => C;
In the test main program, change the declaration of for_c to pad the array with zeros:
for_c : constant C_Binding.Example_t :=
(Length => 5, Bod => (55, 66, 77, 88, 99, others => 0));
For speed, you could instead let the unused part of the array be uninitialized: "others => <>".
If you cannot find a reasonably small maximum size, it should be possible to define the C binding to be generic in the actual size. But that is getting rather messy.
Note that if all the record/struct objects are created on the C side, and the Ada side only reads and writes them, then the maximum size defined in the binding is used only for index bounds checking and can be very large without impact on the memory usage.
In this example I made the Ada side start indexing from 1, but you can change it to start from zero if you want to make it more similar to the C code.
Finally, in the non-discriminated case, I recommend making Example_t a "limited" type ("type Example_t is limited record ...") so that you cannot assign whole values of that type, nor compare them. The reason is that when the C side provides an Example_t object to the Ada side, the actual size of the object may be smaller than the maximum size defined on the Ada side, but an Ada assignment or comparison would try to use the maximum size, which could make the program read or write memory that should not be read or written.

The discriminant is itself a component of the record, and has to be stored somewhere.
This code,
type Integer_Array is array (Natural range <>) of Integer;
type Example (Count : Natural) is record
Bdy : Integer_Array (1 .. Count);
end record;
compiled with -gnatR to show representtion information, says
for Integer_Array'Alignment use 4;
for Integer_Array'Component_Size use 32;
for Example'Object_Size use 68719476736;
for Example'Value_Size use ??;
for Example'Alignment use 4;
for Example use record
Count at 0 range 0 .. 31;
Bdy at 4 range 0 .. ??;
end record;
so we can see that GNAT has decided to put Count in the first 4 bytes, just like the C (well, this is a common C idiom, so I suppose it’s defined behaviour for C struct components to be allocated in source order).
Since this is to be used for interfacing with C, we could say so,
type Example (Count : Natural) is record
Bdy : Integer_Array (1 .. Count);
end record
with Convention => C;
but as Niklas points out the compiler is doubtful about this (it’s warning you that the Standard doesn’t specify the meaning of the construct).
We could confirm at least that we want Count to be in the first 4 bytes, adding
for Example use record
Count at 0 range 0 .. 31;
end record;
but I don’t suppose that would stop a different compiler using a different scheme (e.g. two structures, the first containing Count and the address of the second, Bdy).

C array indices always start at 0.
If you want to duplicate the C structure remember that the discriminant is a member of the record.
type Example (Length : Integer) is record
body : array(0 .. Length - 1) of Integer;
end record;

Related

two dimensional array and pointer arithmetic

I am trying to copy a 2 dimensional array to another 2 dimensional array. Since the name (srcAry) is the address of the first element of the source array, I have been able to print out all the values in the source array using pointer arithmetic in a for loop. I am using the number of rows times the number of columns as the condition to stop looping. If I try to assign the values to the new array using this method I get an error message (error: assignment to expression with array type). Is this possible to do this or am I limited to using two nested for loops with indexes?
...
void copyAry(double *pAry, int numRows, int numCols)
{
double newAry[numRows][numCols];
int end = numRows * numCols;
int ctr = 0;
for( ; ctr < end; ctr++)
// printf("*(pAry + %d) = %.1f\n", ctr, *(pAry + ctr)); //this works fine
{
*(newAry + ctr) = *(pAry + ctr); //this is where I receive error
}
return;
}
...
Thanks in advance.
I would assume that the type of newAry + ctr is not double* as your code assumes, but rather double*[numCols] i.e. a pointer to an array of numCols elements. Which also means that you would advance not one element at a time, but numCols.
Usually you would use memcpy for this kind of low level data copying. Barring that, you might start with double* pNewAry = &newAry[0][0] or some such in order to test the 2d array as a linear sequence of doubles.

Delphi Records - creating a pointer to it

I'm trying to see how I can create a pointer to a simple record.
I have searched for similar topics before posting but it's quite confusing.
I create A & B of which are actual Records.
I then have a variable C which I want to be just a 'pointer to this record'.
I don't want C to store its own value but just a pointer to either A or B.
But whenever C is read/written to,
it's actually being written to either A or B, whichever C is pointing to.
In other words, it's like a pointer to an Object, but I don't need an Object in my case.
Using Delphi 10.3 & 10.4 (if there's any difference), please highlight.
The code below results in Access Violation on first ShowMessage.
procedure TForm1.Button2Click(Sender: TObject);
type
TMyRecord = record
Field1 : integer;
end;
var
A : TMyRecord;
B : TMyRecord;
C : ^TMyRecord; // how to declare this as a pointer?
begin
A.Field1 := 1;
B.Field1 := 2;
C^ := A; // psuedo code to point to A
A.Field1 := 3;
showmessage( C^.Field1.ToString ); // result is 3
C.Field1 := 4;
showmessage( A.Field1.ToString ); // result is 4
C^ := B; // psuedo code to point to A
C.Field1 := 5;
showmessage( B.Field1.ToString ); // result is 5
// anything to free here to avoid memory loss?
end;
C should contain address of A, so make
C := #A;
and the rest of code will work as needed.
Also note that C.Field1 is implicit dereference, it really works as C^.Field1
For now
C^ := A;
denotes assigning contents of A record to memory region addressed by C, but this memory is not allocated - that's why access violation occurs. (To allocate memory, you can make New(C), but this is not needed for your purposes)
Also if you are going to actively use pointer to record, you can define type
PMyRecord = ^TMyRecord;

Increment address of access type as pointer in c using interface.c.pointer?

Some unexpected behavior is noticed: Put_Line(Integer'Image(Var.all)); var:=var+5; -- it gives 1,var+6 then 2 and if var+7 then 0,var+8 then -1, can anyone please explain this?
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C.Pointers;
procedure Access_Pointer_Arithmetic is
type Myarr_Indices is range 1 .. 5;
type Myarr is array (Myarr_Indices range <>) of aliased Integer;
Myarr_Terminator : constant Integer := 0;
package Myarr_Pointer_Arithmetic is new Interfaces.C.Pointers
(Myarr_Indices, Integer, Myarr, Myarr_Terminator);
use Myarr_Pointer_Arithmetic;
Myarr_Var : aliased Myarr := (2, 5, 7, 9, 0);
Var : Myarr_Pointer_Arithmetic.Pointer :=Myarr_Var(Myarr_Var'First)'access;
begin
Put_Line(Integer'Image(Var.all));
var:=var+1;
Put_Line(Integer'Image(Var.all));-- why 1?
var:=var+8;
Put_Line(Integer'Image(Var.all));-- why -1 and some time different 4-7 digits no?
end Access_Pointer_Arithmetic;
Your Ada code is precisely equivalent to this C:
#include <stdio.h>
int main()
{
int arr[5] = {2, 5, 7, 9, 0};
int *p = arr;
printf("%d\n", *p);
p += 1;
printf("%d\n", *p);
p += 8;
printf("%d\n", *p);
return 0;
}
which, when it’s run, produces (on my machine)
2
5
32767
You have told the compiler to reserve space for 5 ints (20 bytes), in which you have put some data. The compiler is free to use the space beyond the end of the array for whatever it likes; it certainly doesn’t belong to you, you have no idea what it’s used for: HANDS OFF!
So when you increment the pointer to what would be the tenth element of the array if you had declared it to be at least 10 elements long, you are addressing undefined data. You have no reason to suppose that it’s an int; it might be part of a character string, it might be the middle of a double, it might be anything. On a desktop machine, it’s unlikely to be a memory location which will cause the machine to catch fire when it’s read; a bit less unlikely in a microcontroller running your toaster.
Writing via the pointer is almost guaranteed to make your program crash, immediately or thousands of instructions later when you will have real trouble finding the bug.
The Ada word for this behaviour of a program is “erroneous”; the C word is, I believe, “undefined”.

Is N-1 the largest term which could be used for Generic in VHDL

I am new to VHDL and I wanted to ask that what generic term could I use If i wanted to write any size of input vector which could be developed?
GENERIC (n1 : integer);
x:IN BIT_VECTOR(n1-1 downto 0);
Is that a correct example?
Your generic has no default value visible.
Your declaration for x is incomplete. It appears to be an entity declarative item with a mode while you don't have a port declaration.
This VHDL code is syntactically and semantically valid:
entity foo is
generic ( n1: integer);
port (
x: in bit_vector(n1-1 downto 0)
);
end entity;
architecture fum of foo is
begin
end architecture;
It will analyze. It can't be elaborated without the value of n1 being known:
entity foo_tb is
constant N_1: integer := 4;
end entity;
architecture fum of foo_tb is
signal x: bit_vector (N_1-1 downto 0);
begin
DUT:
entity work.foo
generic map (n1 => N_1)
port map ( x => x);
end architecture;
Entity foo by itself can't be the top level of an elaborated model because n1 isn't defined for elaboration.
Entity foo_tb can be elaborated, it uses the constant N_1 to supply a value to n1.
foo_tb can even be simulated, but it will exit immediately because there are no pending signal assignments after initialization.
Neither foo nor foo_tb can be synthesize. foo_tb because it has no ports and any logic in it's design hierarchy would be optimized away as unused. foo because it only has an output and is at best a constant.
If foo had multiple ports, with outputs depending on inputs it would be eligible for synthesis or simulation as long as the generic was defined for elaboration.
(And the moral here is to use a Minimal, Complete, and Verifiable example so someone doesn't have to wave their hands around it's shortcomings).
You can use every term, as far as it's result does not exceed the BIT_VECTORS's array range.
BIT_VECTOR definition: type BIT_VECTOR is array (NATURAL range <>) of BIT;
So your term can have results from 0 to 2**32 - 1
Term examples:
4*n1 - 1 downto 0
n1/4 + 8 downto 0
log2ceilnz(n1) - 1 downto 0
2**n1 - 1 downto 0
According to the " Paebbels" comment I edit this answer :
Every time you want to synthesize your code, synthesis tool should know about the size of parameters you used, Otherwise what exactly you want to synthesize ?!!! (what hardware ?!)
If you want to synthesize your top module code which contains a generic parameter in it's own entity, you can assign it with a default value such as the following code :
ENTITY ... IS
GENERIC(n1 : INTEGER := 8);
PORT(
-- use generic parameter
);
END ENTITY;
Also you can use the generic parameter inside architecture ( size of signals, index of loops, ... ).

How do I import a C-function to Ada with pass-by-reference arguments?

I have a C function int func( int a, int* b) that I need to import and use in Ada 95. Where the C function would typically be called in C as c = func(a, &b);
I import C functions all the time into Ada, but have always avoided using functions with pass by reference arguments, but it's finally time to learn.
I would like to know how to declare this function in Ada, and would also like a quick example of using it with declared variables shown (because I'm still a little fuzzy on the Access types).
Thanks all!
In C, int* b can mean a lot of things. Perhaps it's really just a pointer to one variable, but it may also be an array for which int a is the length. This code assumes that int* b is actually just a value that's passed by reference:
with Interfaces.C;
-- ...
package C renames Interfaces.C;
function Func (A : C.int; B : access C.int) return C.int;
pragma Import (Convention => C, Entity => Func,
External_Name => "func");
-- ...
declare
A : C.int := 42;
B : aliased C.int := 23;
C : C.int;
begin
C := Func (A, B'Access);
-- ...
end;
You can use 'Access on aliased variables. This is safe as long as you're sure that the pointer won't be stored on the C side and accessed after the end of life of variable B. (If the C declaration uses the const keyword, you can use access constant on the Ada side, but that's Ada 2005 only.)
You can also use a named type:
-- ...
type Int_Access is access C.int;
function Func (A : C.int; B : Int_Access) return C.int;
-- ...
C := Func (A, B'Unchecked_Access);
-- ...
Now we need to use 'Unchecked_Access because Ada normally does not allow a non-local access type (as Int_Access) to refer to a local variable. If you know what the C code will do with the pointer (like you should), you can use named types to specify that no references to local variables should be passed.
Nota bene 1: If you have a procedure (in C: a function that returns void), you can specify a variable to be passed by reference by using in out in your Ada procedure declaration instead of access. This way, you do not need to worry about access types at all. As before, you need to be sure that the pointer is not stored at the C side.
Nota bene 2: Record types and arrays are passed by reference anyway - unless you specify pragma Convention (C_Pass_By_Copy, Your_Type);. This is a common gotcha when wrapping C functions in Ada.
In addition to (and plagiarizing from flyx) I offer a full solution:
File c_thing.c
#include <stdio.h>
int foo (int a, int * b) {
printf ("A:%d, B %d\n",a, *b);
}
File ada_main.adb
with Interfaces.C;
procedure Ada_Main is
package C renames Interfaces.C;
function Func (A : C.int; B : access C.int) return C.int;
pragma Import (Convention => C, Entity => Func,
External_Name => "foo");
A : C.int := 42;
B : aliased C.int := 23;
R : C.int;
begin
R := Func (A, B'Access);
end Ada_Main;
To Compile (linux):
gcc -c c_thing.c
gnatmake -c ada_main.adb
gnatbind ada_main.ali
gnatlink ada_main.ali c_thing.o
To Run
./ada_main
A:42, B 23

Resources