我最终使用了Interface.C.Pointers
包使其正常工作,这很容易,以下是代码:
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 ;
我测试了上述代码,将C函数中所有_MYREC
元素的n
属性设置为42 + i
并在Ada主体中打印它,它可以正常工作(我得到了42、43、44、45、46)。测试时C函数如下:
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
变量在包创建中是无用但必要的。我假设您总是使用
length
参数与
Value
函数一起检索值。
有关该包的更多信息:
http://www.adaic.org/resources/add_content/standards/05rm/html/RM-B-3-2.html
编辑:原始代码复制了由
P
指向的内存,因此如果您更新数组
A
中的任何内容,则不会在分配的内存中更改。实际上,您应该像编辑后的代码中所示直接使用指针P。
编辑:我对
MYREC
的
str
属性使用了“愚蠢”的
access all Char
,但如果需要,您可以(并且应该)使用来自
Interfaces.C.Pointers
的几乎相同的东西。我测试过了,但不想将其放入答案中,因为它没有添加任何内容。
allocMyRec
函数的Ada代码,还是只是想要类似于该函数但不调用C函数的Ada代码? - ajballocMyRec
的Ada代码,但我想在MYREC_Array
上使用ADA进行操作。 - Florian B.