如何使用pass-by-reference参数将C函数导入Ada?

时间:2012-06-25 13:11:21

标签: ada

我有一个C函数int func( int a, int* b)我需要在Ada 95中导入和使用。其中C函数通常在C中被调用为c = func(a, &b);

我一直将C函数导入Ada,但总是避免使用带引用参数的函数,但最后还是要学习。

我想知道如何在Ada中声明这个函数,并且还想要一个快速示例,将它与显示的声明变量一起使用(因为我对Access类型仍然有点模糊)。

全部谢谢!

2 个答案:

答案 0 :(得分:8)

在C中,int* b可能意味着很多事情。也许它只是一个指向一个变量的指针,但它也可能是一个int a长度的数组。此代码假定int* b实际上只是通过引用传递的值:

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;

您可以在'Access个变量上使用aliased。只要您确定指针不会存储在C端并在变量B的生命周期结束后访问,这是安全的。 (如果C声明使用const关键字,您可以在Ada端使用access constant,但这只是Ada 2005。)

您还可以使用命名类型:

-- ...
type Int_Access is access C.int;
function Func (A : C.int; B : Int_Access) return C.int;
-- ...
C := Func (A, B'Unchecked_Access);
-- ...

现在我们需要使用'Unchecked_Access,因为Ada通常不允许非本地访问类型(如Int_Access)引用局部变量。如果你知道C代码将用指针做什么(就像你应该这样),你可以使用命名类型来指定不应该传递对局部变量的引用。

Nota bene 1:如果你有一个程序(在C中:一个返回void的函数),你可以使用{{1}指定一个通过引用传递的变量在你的Ada程序声明中而不是in out。这样,您根本不需要担心访问类型。和以前一样,你需要确保指针没有存储在C端。

Nota bene 2:记录类型和数组无论如何都是通过引用传递的 - 除非您指定access。在Ada中包装C函数时,这是一个常见的问题。

答案 1 :(得分:4)

除了(和flyx抄袭)我提供了一个完整的解决方案:

档案c_thing.c

#include <stdio.h>

int foo (int a, int * b) {
  printf ("A:%d, B %d\n",a, *b);
}

档案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;

编译(linux):

gcc -c c_thing.c
gnatmake -c ada_main.adb
gnatbind ada_main.ali
gnatlink ada_main.ali c_thing.o

运行

./ada_main 
A:42, B 23