gpt4 book ai didi

c - 将从 C 例程分配的数组传递给 Ada

转载 作者:太空狗 更新时间:2023-10-29 15:35:45 24 4
gpt4 key购买 nike

将结构/记录数组从 Ada 传递到 C 例程是一回事。在这种情况下,内存管理是在 Ada 中完成的。但是在与第三方库接口(interface)时,经常会出现内存管理在 C 部分完成的问题。

例如:对于 C 结构:

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

以下 C 例程分配内存并返回指向具有 n 个元素的 MYREC 数组的指针:

MYREC * allocMyrec(int n);

问题是返回的指针不包含 Ada 中内存安全计算所需的大小信息。

在 Ada 中,我想为 (MYREC *) 指针使用相应的数组定义:

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

相应的(大小感知)Ada-Function allocMyrec 会是什么样子或者什么是正确的策略?

顺便说一句对于一个元素,可以将 C 指针映射到 access MYREC 。这就是 Gnat-Binding 生成器所做的。但这没有帮助。

高度赞赏提示。

最佳答案

我终于使用 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 body,它起作用了(我得到了 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,如编辑后的代码所示。

编辑: 我为 MYRECstr 属性使用了一个“愚蠢的”access all Char 但你如有必要,可以(并且应该)使用 Interfaces.C.Pointers 中几乎相同的内容。我对其进行了测试,但不想将其放入答案中,因为它没有添加任何内容。

关于c - 将从 C 例程分配的数组传递给 Ada,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23364380/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com