传递从C-例程ADA分配的数组 [英] Passing an Array allocated from a C-routine to ADA

查看:157
本文介绍了传递从C-例程ADA分配的数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从ADA到C程序的结构/记录传递数组是一件事。在这种情况下,存储器管理在ADA完成。但是,随着第三方接口库时,往往存在的内存管理在C部分完成的问题。

Passing arrays of structures/records from ADA to C routines is one thing. In this case the memory management is done in ADA. But when interfacing with third party libraries there is often the problem that Memory management is done in the C part.

例如:对于C-结构:

typedef struct _MYREC
{
      int n;
      char *str;
 } MYREC;

下面的C-程序分配内存,并返回一个指向一个MYREC阵列具有n个元素:

the following C-routine allocates Memory and returns a pointer to a MYREC-array with n elements:

MYREC * allocMyrec(int n);

问题是,返回的指针不包含这是需要在ADA内存安全计算大小的信息。

Problem is that the returned Pointer does not contain size-information which is required for memory-safe computation in ADA.

在ADA我想使用的(MYREC *)指针对应的阵列的定义:

in ADA I would like to use the corresponding Array-Definition for the (MYREC *) pointer:

type MYREC_Array is array (Int range <>) of aliased MYREC;
pragma Convention (C, MYREC_Array);

如何将相应的(大小awawre)ADA-功能 allocMyrec 样子或什么是正确的策略?

How would a corresponding (size-awawre) ADA-Function allocMyrec look like or what would be the right strategy?

B.t.w。为一个单元,可以将C-指针访问MYREC 映射。这是蚊蚋,结合发电机做什么。但是,这是没有帮助的。

B.t.w. for one element it is possible to map the C-pointer to access MYREC . That is what the Gnat-Binding generator does. But this is not helpful.

提示高度AP preciated。

Hints highly appreciated.

推荐答案

我终于得到它的工作使用包 Interface.C.Pointers ,还是比较方便的,在这里是code:

I finally got it working using the package Interface.C.Pointers, it is quite easy, here is the code :

with Interfaces.C, Interfaces.C.Pointers ;
use Interfaces.C ;
with Ada.Text_IO ; -- To Check 

procedure MYRECTest is 

    package IIO is new Ada.Text_IO.Integer_IO (Int) ;

    type PChar is access all Char ;

    type MYREC is record
        N : Int ;
        Str : PChar ;
    end record ;
    pragma Convention(C, MYREC); 

    DefaultMyrec : MYREC := (0, null) ; 

    type MYREC_Array is array (Int range <>) of aliased MYREC ;
    pragma Convention(C, MYREC_Array); -- Not sure if useful...

    -- Here is the trick
    package PMYREC is new Interfaces.C.Pointers (Int, MYREC, MYREC_Array, DefaultMyrec) ;

    function AllocMyrec (N : in Int) return PMYREC.Pointer ;
    pragma Import (C, AllocMyrec, "allocMyrec");

    P : PMYREC.Pointer := AllocMyrec(5) ;
    StartP : PMYREC.Pointer := P ; -- Initial pointer
    A : MYREC_Array(0..4) := PMYREC.Value(P, 5) ; -- Here is a copy

begin

    for I in A'Range loop
        -- Real access:
        IIO.Put(P.all.N) ;
        P.all.N := P.all.N + 3 ; -- Here you're really accessing the allocated memory, not just a copy
        PMYREC.Increment(P) ; 
        -- 'Fake' access:
        IIO.Put(A(I).N) ;
        A(I).N := A(I).N + 3 ; -- Here you're accessing a copy, so the modification is not made on the allocated memory
    end loop ;
    Ada.Text_IO.New_Line ;

end MYRECTest ;

我测试了上述code在C函数设置所有 _MYREC 元素的 N 属性 42 + I ,并在阿达体打印出来,它的工作(我得到了42,43,44,45,46)。 C函数看起来像(测试):

I tested the above code setting the n attribute of all _MYREC elements in the C function to 42 + i and printing it in the Ada body, it worked (I got 42, 43, 44, 45, 46). The C function looked like (for test) :

typedef struct _MYREC { 
    int n ;
    char *str ;
} MYREC ;

MYREC * allocMyrec (int n) {
    MYREC *res = malloc(n * sizeof(MYREC)) ;
    int i ;
    for (i = 0 ; i < n ; i++) { 
        res[i].n = 42 + i;
    }
    return res ;
}

DefaultMyrec 变量是无用的,但对于包创建必要的。我以为你总是使用函数与长度参数来检索值。

The DefaultMyrec variable is useless but necessary for the package creation. I assumed you always use the Value function with the length parameter to retrieve value.

更多信息: http://www.adaic.org/resources/add_content/standards/05rm/html/RM-B-3-2.html

编辑:原来的code的制作由 p指向内存的副本所以如果你更新阵列中的任何 A 它不会在分配内存的变化。事实上,你应该直接使用指针P一样显示在编辑code。

The original code was making a copy of the memory pointed by P so if you update anything in the array A it won't be change in the memory allocated. In fact you should directly use the pointer P like shown in the edited code.

编辑:我用了一个'笨'访问的所有字符 STR MYREC 属性,但你可以(也应该)使用几乎从 Interfaces.C.Pointers 如有必要,同样的东西。我测试了它,但不希望把它的答案,因为它没有添加任何东西给它。

I used a 'stupid' access all Char for the str attribute of MYREC but you can (and should) use almost the same stuff from Interfaces.C.Pointers if necessary. I tested it but did not want to put it in the answer because it did not add anything to it.

这篇关于传递从C-例程ADA分配的数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆