LambdaBeta LambdaBeta - 1 month ago 17
C Question

Ada sending byte buffer to c

I'm having an issue with interfacing to C from ada. In particular I have this ada declaration:

type Byte is mod 256; pragma Convention (C, Byte);
type ByteStream is array (Interfaces.C.size_t range <>) of Byte;
pragma Convention (C, ByteStream);
type VoidPointer is access all ByteStream;
type ByteBuffer is
record
data : VoidPointer;
size : Interfaces.C.size_t;
end record;
pragma Convention (C, ByteBuffer);
procedure Free is new Ada.Unchecked_Deallocation (ByteStream, VoidPointer);


and this C declaration:

struct ByteBuffer {
unsigned char *data;
size_t size;
};


and this ada import:

function My_Function (
data : in ByteBuffer)
return Interfaces.C.int;
pragma Import (C, My_Function, "my_function");


and this C declaration:

int my_function(struct ByteBuffer data);


And yet when I debug my code I find a size of (in one example) 110 on the ada side, but 0x7fffffffe750 on the c side. Why is my size_t being mangled? (Note: the data itself is also mangled, but hopefully fixing one will fix the other).

Answer

The in parameter in Ada can use either reference or copy, but it's compiler/structure size dependent.

To force both parties to use pointers (the easiest thing to do here) you can do this:

On the Ada side:

function My_Function (
    data : access ByteBuffer)
    return Interfaces.C.int;
pragma Import (C, My_Function, "my_function");

And on the C side:

int my_function(const struct ByteBuffer *data);

Since ByteBuffer is a constrained array, another info passes: the boundaries which is a pointer (the whole pointer is a "fat" pointer). You could "skip" it on the C side by doing this:

struct ByteBuffer {
    unsigned char *data;
    void *skipit;  // ignore this value
    size_t size;
};

To force Ada to pass by copy, you can use pragma Convention(C_Pass_By_Copy,ByteBuffer) after type declaration (Ada side)

Comments